【问题标题】:Why does the this generic function not call the overriden function为什么这个泛型函数不调用覆盖函数
【发布时间】:2014-03-20 15:31:17
【问题描述】:

如果我有一个基类

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

我很好奇为什么通用版本没有得到Clone()new 版本,而是继承的版本。

是不是 T 类型在满足约束后被删除,然后它只是使用基类来表现?

【问题讨论】:

  • 看看这个question也许能帮上忙。

标签: c# generics


【解决方案1】:

是不是类型 T 在满足约束后被擦除,然后它只是使用基类来表现?

这取决于“T 类型已删除”的含义。它不会像在 Java 中那样被擦除——类型参数在执行时可用,所以如果你写:

Console.WriteLine(typeof(T));

这将打印Bar

但是,编译器需要确定在编译您的第一个Bang 方法时调用哪个方法是该值是Foo 类型还是某个子类型。它必须在此基础上生成调用一个方法的IL。这不像编译器会为每个不同的T 生成一个新的Bang 方法,使用实际类型T 来执行方法解析等。

换句话说,就编译器而言,您的方法相当于:

public static T Bang<T>(Foo source)
where T : Foo
{
    return (T) source.Clone();
}

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

(我假设您了解,就编译器和 CLR 而言,您的两个 Clone 方法大多不相关;它们碰巧具有相同的名称,但其中一个不会以多态方式覆盖另一个。)

【讨论】:

  • 答案如我所料。是的,我确实理解存在差异。这是第三方封闭源代码库中的错误。他们应该使用 override 而不是 new 但我只是对编译器处理它的方式感到好奇。
【解决方案2】:

简而言之,newoverride 不同。 new 表示方法的遮蔽,表示派生实现已更改,但基本实现保持不变。 override 也将更改基本实现。

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-25
    • 2019-07-24
    • 2020-03-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多