为什么 C# 调用错误的重载?
我有以下代码,确实做有趣的东西:
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>)");
}
}
如您所见,Child
中的DoSomething
方法被覆盖正确。
以下代码的输出非常出乎意料:
...
Child c = new Child();
var list = new List<string> { "Hello", "World!" };
c.DoSomething(list);
...
打印 Child.DoSomething(IEnumerable
而将 Parent
引用分配给 c
会生成正确的输出:
...
Parent c = new Child();
var list = new List<string> { "Hello", "World!" };
c.DoSomething(list);
...
打印 Child.DoSomething(IEnumerable
为什么会发生这种情况?!
I have following code that really does funny stuff:
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>)");
}
}
As you can see, the DoSomething
method in Child
is overridden correctly.
The output of the following code is very unexpected:
...
Child c = new Child();
var list = new List<string> { "Hello", "World!" };
c.DoSomething(list);
...
Prints Child.DoSomething(IEnumerable<object>)
Whereas assinging a Parent
reference to c
generates the correct output:
...
Parent c = new Child();
var list = new List<string> { "Hello", "World!" };
c.DoSomething(list);
...
Prints Child.DoSomething(IEnumerable<string>)
Why does this happen?!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
发生这种情况是因为 C# 编译器遵循规范 :)
规范规定,如果在派生类型中声明的任何方法都适用,则在基类中最初声明的任何方法(即使它们在派生类型中被重写)派生类型)从候选集中删除。
现在,因为您使用的是 C# 4(大概),所以存在从
List
到IEnumerable
我有一篇关于重载的文章,其中讨论了这个问题和其他一些奇怪的问题。
我建议你不要跨类型层次结构超载——这会令人困惑。
It happens because the C# compiler obeys the spec :)
The specification says that if any method declared in a derived type is applicable, any methods originally declared in a base class (even if they're overridden in the derived type) are removed from the set of candidates.
Now because you're using C# 4 (presumably) there's an implicit conversion from
List<string>
toIEnumerable<object>
so yourChild.DoSomething(IEnumerable<object>)
overload is applicable, and the compiler never really considers the one usingIEnumerable<string>
.I have an article about overloading which goes into this and some other oddities.
I advise you not to overload across type hierarchies - it's confusing.
可能的解决方案,尝试:
posible soulution, try:
@Lasse,
你写的
我不确定我是否理解你在说什么,但在第二种情况下,由于实例是 Child 的实例并且被调用的方法是虚拟的,因此方法解析是在运行时而不是编译时完成的,并且事实上,调用的是子进程的方法。
至于方法解析规则。难道不应该选择更具体的方法吗?我知道现阶段这是一个有争议的问题。在 3.5 和 2 中,它将选择更具体的方法。
@Lasse,
you wrote
I'm not sure if I understand what you're saying, but in the second case, since the instance is an instance of Child and the method being called is virtual, the method resolution is done at run time and not compile time, and in fact it is the child's method that is being called.
As regards method resolution rules. Shouldn't it choose a more specific method? I know it's a moot point at this stage. in 3.5 and 2 it would pick the more specific method.