为什么这个泛型函数不调用重写函数
本文关键字:函数 重写 调用 泛型 为什么 | 更新日期: 2023-09-27 17:51:04
如果有一个基类
class Foo : IClonable {
public object virtual Clone(){ return new Foo(); }
}
和一个子类错误地用new
代替override
覆盖clone。这是我正在尝试解决的第三方库中的一个错误的简化。
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
返回。
我很好奇为什么通用版本没有得到Clone()
的new
版本,而是继承的版本。
是否类型T
在满足约束后被擦除,然后它只是使用基类的行为?
是否是类型T在满足约束后被擦除,然后它只是使用基类的行为?
这取决于你所说的"类型T
被擦除"是什么意思。它不像在Java中那样被擦除——类型参数在执行时可用,所以如果你写:
Console.WriteLine(typeof(T));
将打印Bar
。
然而,编译器需要确定在编译第一个Bang
方法时调用哪个方法,该值是Foo
类型或某些子类型。它必须在此基础上生成调用的一个方法。它不像编译器为每个不同的T
生成一个新的Bang
方法,使用实际类型T
来执行方法解析等。
换句话说,就编译器而言,你的方法相当于:
public static T Bang<T>(Foo source)
where T : Foo
{
return (T) source.Clone();
}
注意参数类型从T
到Foo
的变化,因为这是编译器必须处理的所有信息。
(我假设你明白你的两个Clone
方法就编译器和CLR而言大多是不相关的;它们碰巧有相同的名称,但其中一个不会在多态上覆盖另一个。
总之,new
和override
是不一样的。new
表示遮蔽方法的,这意味着派生实现发生了变化,但基本实现保持不变。override
也将改变基本实现。
在隐藏中,只更改派生类型的实现。这意味着如果对象的类型为基类型,它将使用基方法。您的泛型约束类型T
为Foo
的基本类型。
var bar = new Bar();
var result = bar.Clone(); // returns Bar
var result2 = ((Foo)bar).Clone(); // returns Foo