为什么方法重载在这个C#程序中不起作用?

namespace test { class Program { static void Main(string[] args) { Derived obj = new Derived(); int i = 10; obj.Foo(i); Console.ReadLine(); } } class Base { public virtual void Foo(int i) { Console.WriteLine("Base:Foo()"); } } class Derived:Base { public override void Foo(int i) { Console.WriteLine("Foo(int)"); } public void Foo(object i) { Console.WriteLine("Foo(object)"); } } } 

根据我的程序输出应该是Foo(int)但是输出来自Foo(对象)请帮助我理解输出中的差异

好问题,我可以重现你的结果。 如果看一下C# 规范,就会发现以下片段:

7.5.3过载分辨率

例如,方法调用的候选集不包括标记为override的方法(第7.4节),如果派生类中的任何方法适用(第7.6.5.1节),则基类中的方法不是候选方法。

7.4会员查询

否则,该集由T中名为N的所有可访问(§3.5)成员组成,包括inheritance成员和对象中名为N的可访问成员。 如果T是构造类型,则通过替换类型参数来获得成员集,如第10.3.2节中所述。 包含覆盖修饰符的成员将从集合中排除。

7.6.5.1方法调用

候选方法集合被简化为仅包含来自大多数派生类型的方法:对于集合中的每个方法CF,其中C是声明方法F的类型, 所有在基本类型C中声明的方法都从集合。 此外,如果C是除object之外的类类型,则从集合中删除在接口类型中声明的所有方法。

听起来有点复杂? 即使是C#设计师似乎也这么认为并提出了“有用”的说明:

7.6.5.1方法调用

上面描述的解析规则的直观效果如下: 要定位由方法调用调用的特定方法 ,请从方法调用指示的类型开始,然后继续inheritance链,直到至少一个适用的,可访问的,非覆盖为止找到方法声明 。 然后对在该类型中声明的适用的,可访问的,非重写方法集执行类型推断和重载解析,并调用由此选择的方法。 如果未找到任何方法,请尝试将调用作为扩展方法调用进行处理。

如果我们看一下你的派生类,我们会看到两种可能的C#方法:

  A) public override void Foo(int i) B) public void Foo(object i) 

让我们使用最后一份清单!

适用性 – A和B都适用 – (两者都是无效的,都被命名为’Foo’,两者都可以接受整数值)。 辅助function – A和B都可访问(公共) 覆盖仅覆盖B。

但是等一下你可能会说! A比B更具体!

正确,但只有我们忽视选项A 之后才能考虑这个问题。正如Eric Lippert(其中一位设计师)所说, Closer总是比远离更好。 (谢谢Anthony Pegram)

附录

始终有’new’关键字 :

 class Derived : Base { public new void Foo(int i) { Console.WriteLine("Foo(int)"); } public void Foo(object i) { Console.WriteLine("Foo(object)"); } } 

虽然最好的细节留给另一个问题!

简单数据类型int来自object。 您正在覆盖该函数并重载参数列表。 由于函数名称与不同的签名相同,因此编译器允许这样做。 对于简单对象,我将图像中最基本forms的参数签名的一个副本存储在方法表中。