为什么这个泛型函数不调用重写函数

本文关键字:函数 重写 调用 泛型 为什么 | 更新日期: 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();
}

注意参数类型从TFoo的变化,因为这是编译器必须处理的所有信息。

(我假设你明白你的两个Clone方法就编译器和CLR而言大多是不相关的;它们碰巧有相同的名称,但其中一个不会在多态上覆盖另一个。

总之,newoverride是不一样的。new表示遮蔽方法的,这意味着派生实现发生了变化,但基本实现保持不变。override也将改变基本实现。

在隐藏中,只更改派生类型的实现。这意味着如果对象的类型为基类型,它将使用基方法。您的泛型约束类型TFoo的基本类型。

var bar = new Bar();
var result = bar.Clone(); // returns Bar
var result2 = ((Foo)bar).Clone(); // returns Foo