对约束泛型类型参数的继承

Vir*_*oid 27 c# generics

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

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

示例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
  }

}
Run Code Online (Sandbox Code Playgroud)

编辑:一些代码来说明如何使用它的示例.考虑以下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");
  }
}
Run Code Online (Sandbox Code Playgroud)

和调用代码:

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

FooProxy<FooY> fooYProxy = new FooProxy<FooY>();
fooYProxy.Y = "test Y";
fooYProxy.Bar();
Run Code Online (Sandbox Code Playgroud)

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

编辑:根据Pete OHanlon的回答修改:使Bar()方法成为虚拟.

Meh*_*ari 46

因为你做不到.泛型不是模板.您不应该像C++模板一样考虑它们并期望相同的行为.它们是根本不同的概念.

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

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

类型参数不能直接用于声明基类(第10.2.4节)或接口(第13.1.3节).

更新:

我明白你想做什么和它的用途.这是C++模板的传统用例.具体来说,如果可以使用C#泛型,像Moq这样的东西可以从中受益.问题是,C++模板是编译时"查找和替换"构造,而C#泛型是运行时的东西.

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

class Test<T> where T : class {
    // whatever contents it might have...
} 
Run Code Online (Sandbox Code Playgroud)

仅单个IL将在编译时被发射,并在运行时间,JIT编译器将产生一个单一的所有引用类型的类型参数的本机代码.这与C++模板完全不同,其中本机代码将单独发出T(它受到优化,但从概念上讲,它们是完全独立的代码片段).

  • 我想要upvote,但我认为你的钱,C++模板不是C#泛型...... (2认同)

Pet*_*lon 7

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

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

public virtual void Bar() {}
Run Code Online (Sandbox Code Playgroud)