我有以下的代码,真的不 好笑的东西:
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>)
为什么这会发生?!
它发生是因为C#编译器服从规范:)
规范说如果在派生类型中声明的任何方法适用,则从候选集中删除最初在基类中声明的任何方法(即使它们在派生类型中被覆盖).
现在因为你正在使用C#4(大概),所以有一个隐式转换List<string>,IEnumerable<object>所以你的Child.DoSomething(IEnumerable<object>)重载是适用的,编译器从来没有真正考虑使用它IEnumerable<string>.
我有一篇关于重载的文章,其中涉及到这个和其他一些奇怪的内容.
我建议你不要超越类型层次结构 - 这是令人困惑的.