这是通过接口公开通用基类方法的好方法吗?

时间:2010-04-09 01:04:13

标签: c# generics oop interface

我正在尝试为抽象通用基类提供接口。我希望在接口上公开一个使用泛型类型的方法,但其实现最终由从我的抽象泛型库继承的类处理。

但是我不希望子类必须向下转换才能使用泛型类型(因为他们已经知道类型应该是什么)。

这是我现在可以看到的唯一方式的简单版本。

public interface IFoo
{
    void Process(Bar_base bar);
}

public abstract class FooBase<T> : IFoo 
    where T : Bar_base
{
    abstract void Process(T bar);

    // Explicit IFoo Implementation
    void IFoo.Process(Bar_base bar)
    {
        if (bar == null) throw new ArgumentNullException();

        // Downcast here in base class (less for subclasses to worry about)
        T downcasted_bar = bar as T;
        if (downcasted_bar == null)
        {
            throw new InvalidOperationException(
                          string.Format("Expected type '{0}', not type '{1}'",
                                        T.ToString(), bar.GetType().ToString());
        }

        //Process downcasted object.
        Process(downcasted_bar);            
    }

}

然后FooBase的子类看起来像这样......

public class Foo_impl1 : FooBase<Bar_impl1>
{
     void override Process(Bar_impl1 bar)
     {
         //No need to downcast here!
     } 
}

显然这不会为我提供编译时类型检查,但我认为它可以完成工作......

问题:
 1.我认为这会起作用吗?  这是最好的方法吗?
 3.这样做有什么问题?
 你能提出一个不同的方法吗?

谢谢!


编辑:在回答许多答案时,要求IFoo不是Generic。我需要能够操纵一组IFoo对象,而不管它们使用的泛型类型。


编辑:努力澄清这个原因...

Bar_base包含对IFoo类型的引用。并且必须调用process方法来验证它包含的数据。可以将IFoo视为包含Bar_base派生对象的验证逻辑的对象。当对Bar_base对象的有效性提出质疑时,它会在其IFoo引用上调用Process来验证自身。

IFoo不能通用的原因是我需要能够引用独立于Bar_base类的IFoo集合。

我将尝试使用两个接口的方法,一个包含Process方法的Generic,另一个不包含非泛型的接口。

4 个答案:

答案 0 :(得分:1)

在IFoo不能通用的情况下,在这种情况下,通常有两个接口IFoo<T>和IFoo,其中IFoo使用支持的最大基类。想想IEnumerable<T>和IEnumerable。非泛型版本通常作为接口重载隐藏,因此只有在通过非泛型接口访问类时才会发挥作用。

答案 1 :(得分:1)

鉴于你的约束条件是T类型为Bar_base,并且(在你的例子中)只使用T代表进程(T bar),我不确定你为什么要使用泛型。如果

abstract Process(Bar_base bar)

就是你所需要的,然后这应该足以用

覆盖类
void override Process(Bar_impl1 bar)

和你的抽象类Bar_base是一个足够的类型约束。

除非我错过了什么......

另一个有用的技巧是提供通用和非通用接口定义,其中非泛型提供非泛型访问方法和属性,而泛型接口仅提供需要泛型类型的其他方法和/或属性。客户端可以指定任一接口,具体取决于它们是否能够共享泛型类型。

interface IFoo
{
...
}

interface IFoo<T> : IFoo where T : Bar_base
{
...
}

但在这种情况下,我不确定这是否能满足您的需求。

答案 2 :(得分:0)

你可以让IFoo通用:

public interface IFoo<T> where T : Bar_base
{
    void Process(T bar);
}

答案 3 :(得分:0)

您不仅仅使用通用接口的原因: -

public interface IFoo<T>
  where T:Bar_base
{
    void Process(T bar);
}