为什么这个泛型方法调用基类方法,而不是派生类方法?

时间:2011-11-29 12:29:39

标签: c# generics

以下代码:

class B
{
    public String G() { return "B.G()"; }
}

class D : B
{
    public String G() { return "D.G()"; }
}

class TestCompile
{
    private static String TestG<T>(T b) where T: B 
    {
        return b.G();
    }

    static void Main(string[] args)
    {
        TestG(new D());
    }
}

结果为B.G(),而类似C ++代码的结果为D.G()

为什么会出现这种差异?

4 个答案:

答案 0 :(得分:9)

使用override关键字:

class B
{
    public virtual String G() { return "B.G()"; }
}

class D : B
{
    public override String G() { return "D.G()"; }
}

如果没有override关键字,则继承的方法不会替换基本方法。

没有覆盖:

D obj = new D();
obj.G(); // "D.G()"
((B)obj).G(); // "B.G()"

使用覆盖:

D obj = new D();
obj.G(); // "D.G()"
((B)obj).G(); // "D.G()"

答案 1 :(得分:6)

C#泛型只编译一次:编译泛型时。 (考虑一下:C#允许你使用List<T>而不看其实现。)在这里,它从where T: B子句看到参数是B,因此它调用B.G }。

每次调用C ++模板时都会编译它们。当您键入TestG<D>()时,TestG的全新副本将使用T = D进行编译。在调用时,编译器会看到D有自己的G方法并调用它。

C#generic的C ++等价物是

template<typename T>
string TestG(T t)
{
    B& b = static_cast<B&>(t); // force `t` into a `B`
    return b.G();
}

其他人关于使用virtual的评论同样适用于C#和C ++。我只是在解释为什么C ++与C#的行为不同。

答案 2 :(得分:3)

因为你忽略了将B.G标记为virtual,将D.G标记为override

你收到了这个编译器警告:

  

CS0108:'D.G()'隐藏继承成员'B.G()'。如果想要隐藏,请使用new关键字。

但你选择忽略它。我希望C ++开发人员能做得更好! :)

答案 3 :(得分:0)

这是因为参数b位于B类型参考中。如果您将b投射到D,则会调用D上的函数。