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

时间:2014-03-20 15:31:17

标签: c# generics

如果我有基类

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

我很好奇为什么通用版本不会获得newClone()而是继承版本。

是否在满足约束后删除类型T,然后它只是使用基类行为?

2 个答案:

答案 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)

简而言之,newoverride不同。 new表示方法的 shadowing ,这意味着派生的实现已更改但基本实现保持不变。 override也会更改基本实现。

在阴影中,仅更改派生类型的实现。这意味着如果对象被键入为基类型,它将使用基本方法。您的通用约束类型T类型为基本类型Foo

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