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

时间:2009-09-14 09:44:48

标签: 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
  }

}

编辑:更多代码来说明如何使用它的示例。考虑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时,将重用FooProxy覆盖Bar()方法中的代码。

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

3 个答案:

答案 0 :(得分:46)

因为你做不到。泛型不是模板。您不应该像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编译器会为所有引用类型参数生成单个本机代码。这与C ++模板完全不同,其中本地代码将分别为每个T发出(它受到优化,但从概念上讲,它们是完全独立的代码片段。)

答案 1 :(得分:7)

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

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

public virtual void Bar() {}

答案 2 :(得分:1)

因为Foo是抽象类型。

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

您也可以使用界面来做我想要做的事情。

编辑:

在第二次考虑你的代码时,没有任何意义。您需要创建 GENERIC 类型的基类,然后从中派生以实现您要执行的操作。这也会让人更有意义......

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