如果我有基类
class Foo : IClonable {
public object virtual Clone(){ return new Foo(); }
}
并且子类错误地使用new
而不是override
覆盖克隆。这是我尝试解决的第三方库中的错误的简化。
class Bar : Foo {
public new Clone() { return new Bar(); }
}
然后我有两种方法
public static T Bang(T source)
where T : Foo
{
return (T) source.Clone();
}
和
public static Bar Bang(Bar source)
{
return (Bar) source.Clone();
}
现在,如果我使用Bar
的实例调用第一个,我会得到Foo
。如果我调用第二个,我会回复Bar
。
我很好奇为什么通用版本不会获得new
版Clone()
而是继承版本。
是否在满足约束后删除类型T
,然后它只是使用基类行为?
答案 0 :(得分:1)
是否在满足约束后删除了类型T,然后它只是使用基类行为?
这取决于“类型T
被删除”的含义。它没有像在Java中那样被删除 - 类型参数在执行时可用,所以如果你写:
Console.WriteLine(typeof(T));
将打印Bar
。
但是,编译器需要确定在编译第一个Bang
方法时要调用的方法是值为Foo
类型或某个子类型。它必须基于此生成IL调用一个方法。它不像编译器为每个不同的Bang
生成一个新的T
方法,使用实际类型T
来执行方法解析等。
换句话说,就编译器而言,您的方法等同于:
public static T Bang<T>(Foo source)
where T : Foo
{
return (T) source.Clone();
}
请注意参数类型从T
更改为Foo
,因为这是编译器必须继续的所有信息。
(我假设您理解,就编译器和CLR而言,您的两个Clone
方法大多不相关;它们碰巧具有相同的名称,但是其中一个不会覆盖其他多态。)
答案 1 :(得分:1)
简而言之,new
与override
不同。 new
表示方法的 shadowing ,这意味着派生的实现已更改但基本实现保持不变。 override
也会更改基本实现。
在阴影中,仅更改派生类型的实现。这意味着如果对象被键入为基类型,它将使用基本方法。您的通用约束类型T
类型为基本类型Foo
。
var bar = new Bar();
var result = bar.Clone(); // returns Bar
var result2 = ((Foo)bar).Clone(); // returns Foo