我知道不可能从泛型类型参数继承,但是在为抽象类型的派生类实现公共代理时它会很方便: - )
有谁知道为什么这是不可能的?
示例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()方法成为虚拟。
答案 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();
}