为什么C#调用错误的重载?

Fai*_* S. 7 c# overriding

我有以下的代码,真的 好笑的东西:

class Parent {
    public virtual void DoSomething(IEnumerable<string> list) {
        Console.WriteLine("Parent.DoSomething(IEnumerable<string>)");
    }
}

class Child : Parent {
    public override void DoSomething(IEnumerable<string> list) {
        Console.WriteLine("Child.DoSomething(IEnumerable<string>)");
    }

    public void DoSomething(IEnumerable<object> list) {
        Console.WriteLine("Child.DoSomething(IEnumerable<object>)");
    }
}
Run Code Online (Sandbox Code Playgroud)

如您所见,正确覆盖了DoSomething方法Child.

以下代码的输出非常意外:

...
Child c = new Child();
var list = new List<string> { "Hello", "World!" };
c.DoSomething(list);
...
Run Code Online (Sandbox Code Playgroud)

打印 Child.DoSomething(IEnumerable<object>)

而协助Parent引用c生成正确的输出:

...
Parent c = new Child();
var list = new List<string> { "Hello", "World!" };
c.DoSomething(list);
...
Run Code Online (Sandbox Code Playgroud)

打印 Child.DoSomething(IEnumerable<string>)

为什么这会发生?!

Jon*_*eet 9

它发生是因为C#编译器服从规范:)

规范说如果在派生类型中声明的任何方法适用,则从候选集中删除最初在基类中声明的任何方法(即使它们在派生类型中被覆盖).

现在因为你正在使用C#4(大概),所以有一个隐式转换List<string>,IEnumerable<object>所以你的Child.DoSomething(IEnumerable<object>)重载是适用的,编译器从来没有真正考虑使用它IEnumerable<string>.

我有一篇关于重载文章,其中涉及到这个和其他一些奇怪的内容.

我建议你不要超越类型层次结构 - 这是令人困惑的.

  • 我认为这背后有充分的理由,但我认为这是规范的一个不幸的部分.它打破了最少惊喜的原则. (4认同)