任何人都可以这么好并解释为什么这段代码会显示Derived.DoWork(double)
。我可以为这种行为提出一些解释,但我希望有人为我澄清这一点。
using System;
public class Base
{
public virtual void DoWork(int param) {
Console.WriteLine("Base.DoWork");
}
}
public class Derived : Base
{
public override void DoWork(int param) {
Console.WriteLine("Derived.DoWork(int)");
}
public void DoWork(double param) {
Console.WriteLine("Derived.DoWork(double)");
}
public static void Main() {
int val = 5;
Derived d = new Derived();
d.DoWork(val);
}
}
答案 0 :(得分:10)
Eric lippert过去经常说"Closer is better"。
首先在派生类中声明的方法比在基类中首次声明的方法更接近。
因此,从上面的链接来看,派生类更接近,因此选择了它。
谨慎实施此行为是为了避免Brittle base class problem
为了完整性,我将分享子弹:
首先在派生类中声明的方法比在基类中首次声明的方法更接近。
嵌套类中的方法比包含类中的方法更接近。
接收类型的任何方法都比任何扩展方法更接近。
在嵌套命名空间中的类中找到的扩展方法比在外部命名空间中的类中找到的扩展方法更接近。
在当前命名空间的类中找到的扩展方法比在using指令提到的命名空间中的类中找到的扩展方法更接近。
在using指令中提到的命名空间中的类中找到的扩展方法(其中指令位于嵌套命名空间中)比在using指令中提到的命名空间中的类中找到的扩展方法更接近在外部名称空间中。
答案 1 :(得分:4)
此行为在C#语言规范中定义,特别是第7.5.3节“重载解析”。这是一个link to an older version,否则请参考本地应该具有的 CSharp语言规范.docx ,例如 C:\ Program Files(x86)\ Microsoft Visual Studio 12.0 \ VC #\ Specifications \ 1033 \ CSharp Language Specification.docx 。
在这种情况下,排除了标记为覆盖的方法,因此double
重载是唯一有效的选项(强调我的):
这些上下文中的每一个都定义了候选函数成员集 和自己独特方式的参数列表,如中所述 上面列出的部分中的详细信息。例如,的集合 方法调用的候选者不包括标记的方法 覆盖(第7.4节),并且基类中的方法不是候选者(如果有的话) 派生类中的方法适用(第7.6.5.1节)。
答案 2 :(得分:1)
这种行为显然是设计出来的:
'在选择重载时,如果在派生类中声明了任何兼容方法,则忽略在基类中声明的所有签名 - 即使它们在同一派生类中被重写!&# 39; http://social.msdn.microsoft.com/Forums/vstudio/en-US/a70b25d4-f310-4d06-9dc2-a453f822f4f3/function-not-getting-called-when-overloading-the-function-of-base-class-in-derived-class-with?forum=csharpgeneral