【问题标题】:Is this a good way to expose generic base class methods through an interface?这是通过接口公开通用基类方法的好方法吗?
【发布时间】:2010-04-09 01:04:13
【问题描述】:

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

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

这是我目前看到的让它工作的唯一方法的简单版本。

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.这个功能会像我想的那样吗?
2. 这是最好的方法吗?
3. 这样做有什么问题?
4. 你能建议一种不同的方法吗?

谢谢!


编辑:针对许多答案,要求 IFoo 不是通用的。我需要能够操作 IFoo 对象的集合,而不管它们使用什么泛型类型。


编辑:为了澄清这个原因......

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

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

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

【问题讨论】:

  • 如果你重写 Process(...) 函数,你打算如何执行基类中的代码?您如何看待使用中的代码流?
  • @galford13x - 我的印象是 IFoo.Process 方法的显式实现将在调用接口引用时被调用。否则,基类 Process 方法是抽象的,所以我希望我的继承类实现。
  • 你能解释一下为什么非通用 IFoo 是一个要求吗?
  • 通过泛型/非泛型接口对,我已经成功地将 List 与 IFoo 成员的异构组合一起使用。列表的客户端只能使用非泛型接口中定义的方法。不过,类 Foo 可能需要在管理上变得相当棘手。
  • 是的,看起来这可能会奏效,因为在需要验证自身时,需要访问 Process 方法的唯一对象实际上是 Bar_base 派生对象。明天试试。

标签: c# generics oop interface


【解决方案1】:

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

【讨论】:

  • +1 将尝试两种接口方法,看看它是否适合我。
【解决方案2】:

鉴于您的 T 是 Bar_base 类型的约束,并且(在您的示例中)仅将 T 用于 Process(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
{
...
}

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

【讨论】:

  • +1 将尝试两种接口方法,看看它是否适合我。
  • 不得不接受丹的回答,因为他发布了他的第一个。但是感谢您的帮助!
【解决方案3】:

你可以让 IFoo 通用:

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

【讨论】:

    【解决方案4】:

    您不只是使用通用接口的任何原因:-

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-06-10
      • 2013-06-20
      • 2021-05-27
      • 1970-01-01
      • 2019-11-18
      • 1970-01-01
      • 2015-05-06
      相关资源
      最近更新 更多