我有以下代码,真正 搞笑的东西:
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>)");
}
}
如您所见,DoSomething
中的Child
方法被正确覆盖。
以下代码的输出非常意外:
...
Child c = new Child();
var list = new List<string> { "Hello", "World!" };
c.DoSomething(list);
...
打印Child.DoSomething(IEnumerable<object>)
而Parent
c
引用...
Parent c = new Child();
var list = new List<string> { "Hello", "World!" };
c.DoSomething(list);
...
会产生正确的输出:
Child.DoSomething(IEnumerable<string>)
打印{{1}}
为什么发生?!
答案 0 :(得分:9)
这是因为C#编译器遵守规范:)
规范说如果在派生类型中声明的任何方法都适用,那么在基类中最初声明的任何方法(即使它们在派生类型中被重写)都会从集合中删除候选人。
现在因为您正在使用C#4(可能),从List<string>
到IEnumerable<object>
进行了隐式转换,因此您的Child.DoSomething(IEnumerable<object>)
重载适用,并且编译器从未真正考虑使用IEnumerable<string>
。
我有一个article about overloading进入这个以及其他一些奇怪的事情。
我建议你不要在类型层次结构中超载 - 这很令人困惑。
答案 1 :(得分:0)
posible soulution,试试:
class Child : Parent {
public override void DoSomething(IEnumerable<string> list) {
Console.WriteLine("Child.DoSomething(IEnumerable<string>)");
}
public void DoSomething(IEnumerable<object> list) {
if(list is IEnumerable<string>){
DoSomething((IEnumerable<string>)list);
return;
}
else
Console.WriteLine("Child.DoSomething(IEnumerable<object>)");
}
}
答案 2 :(得分:0)
@Lasse,
你写了因为编译器只使用它知道的对象的类型,并且它只知道对象支持Parent中的内容,因此在解析方法调用时只有一个方法可用。
我不确定我是否理解你所说的内容,但在第二种情况下,由于实例是Child的一个实例,被调用的方法是虚拟的,因此方法解析在运行时完成而不是编译时间,实际上它是被调用的孩子的方法。
关于方法解决规则。它不应该选择更具体的方法吗?我知道这是现阶段的一个有争议的问题。在3.5和2中,它会选择更具体的方法。