【问题标题】:Inheritance on a constrained generic type parameter受约束的泛型类型参数的继承
【发布时间】:2009-09-14 09:44:47
【问题描述】:

我知道不可能从泛型类型参数继承,但是在为抽象类型的派生类实现通用代理时会很方便:-)

有人知道为什么这是不可能的吗?

示例 C#:

abstract class Foo
{
  public virtual void Bar()
  {
     // nop
  }
}

class FooProxy<TFoo> : TFoo
  where TFoo : Foo
{

  public override void Bar()
  {
    // do some stuff before
    base.Bar();
    // do some stuff after
  }

}

编辑:更多代码来说明如何使用它的示例。考虑 Foo 的以下派生词:

class FooX : Foo
{
  public string X { get; set; }
  public override void Bar()
  {
    Console.WriteLine("Doing Bar X");
  }
}

class FooY : Foo
{
  public string Y { get; set; }
  public override void Bar()
  {
    Console.WriteLine("Doing Bar Y");
  }
}

以及调用代码:

FooProxy<FooX> fooXProxy = new FooProxy<FooX>();
fooXProxy.X = "test X";
fooXProxy.Bar();

FooProxy<FooY> fooYProxy = new FooProxy<FooY>();
fooYProxy.Y = "test Y";
fooYProxy.Bar();

在使用 FooX 和 FooY 时,将重用 Bar() 方法的 FooProxy 覆盖中的代码。

编辑:根据 Pete OHanlon 的回答修改:将 Bar() 方法设为虚拟。

【问题讨论】:

    标签: c# generics


    【解决方案1】:

    因为你不能。泛型不是模板。您不应将它们视为 C++ 模板并期望它们具有相同的行为。它们是根本不同的概念。

    C# 规范明确禁止将类型参数用作基类:

    C# 3.0 语言规范:类型参数(§4.5)

    类型参数不能直接用于声明基类(§10.2.4)或接口(§13.1.3)。

    更新:

    我了解您想要做什么以及它的用途。这是 C++ 模板的传统用例。具体来说,如果使用 C# 泛型可以做到这一点,那么像 Moq library 这样的东西可以从中受益。问题是,C++ 模板是编译时的“查找和替换”结构,而 C# 泛型是运行时的东西。

    为了证明这个事实,对于这个类:

    class Test<T> where T : class {
        // whatever contents it might have...
    } 
    

    在编译时和运行时只会发出一个 IL,JIT 编译器将为所有引用类型类型参数生成 single 本机代码。这根本不像 C++ 模板,其中将为每个 T 分别发出本机代码(它需要优化,但从概念上讲,它们是完全独立的代码片段)。

    【讨论】:

    • 我想要赞成票,但我认为你的钱,C++ 模板不是 C# 泛型......
    • 换句话说,一个对象不可能同时符合派生的通用类二进制布局(这要求基子对象是固定的、一致的大小)和基类二进制布局。 “固定大小基础”要求是由 CLR 强加的,并不是基本要求——可以存储每个子对象的偏移量,这也是支持多重虚拟继承的语言所需要的——但 .NET 选择了避免这种额外的并发症。
    【解决方案2】:

    您不能从泛型类型参数继承,因为类型在编译时是未知的,因此编译器无法确定超类是什么。我意识到,乍一看,编译器可以弄清楚 是什么这一事实似乎表明它应该能够弄清楚 T 是什么,但这两件事是不同的。

    此外,您在 Bar 中存在逻辑问题。你不能调用 base.Bar 因为这是一个抽象类型。为了纠正这个问题,您必须将 Foo 中的实现更改为

    public virtual void Bar() {}
    

    【讨论】:

      【解决方案3】:

      因为 Foo 是一种抽象类型。

      如果你在一个类中实现了 Foo 然后在模板中使用它,那么你可以这样做。

      我相信你也可以使用一个界面来做你想做的事情。

      编辑:

      再次考虑查看您的代码,这没有任何意义。您需要创建一个 GENERIC 类型的基类,然后从中派生以实现您想要做的事情。它也会让地狱变得更有意义......

      abstract class Foo<T>  
      {  
          public virtual void Bar();  
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多