C#中方法重载的不同行为

我正在浏览C#Brainteasers( http://www.yoda.arachsys.com/csharp/teasers.html )并遇到一个问题:这段代码的输出应该是什么?

class Base { public virtual void Foo(int x) { Console.WriteLine ("Base.Foo(int)"); } } class Derived : Base { public override void Foo(int x) { Console.WriteLine ("Derived.Foo(int)"); } public void Foo(object o) { Console.WriteLine ("Derived.Foo(object)"); } } class Test { static void Main() { Derived d = new Derived(); int i = 10; d.Foo(i); // it prints ("Derived.Foo(object)" } } 

但是,如果我将代码更改为

 class Derived { public void Foo(int x) { Console.WriteLine("Derived.Foo(int)"); } public void Foo(object o) { Console.WriteLine("Derived.Foo(object)"); } } class Program { static void Main(string[] args) { Derived d = new Derived(); int i = 10; d.Foo(i); // prints Derived.Foo(int)"); Console.ReadKey(); } } 

我想为什么在inheritance而不是inheritance时输出会发生变化; 为什么方法重载在这两种情况下表现不同?

正如我在答案页面中指定的那样:

打印Derived.Foo(object) – 在选择重载时,如果在派生类中声明了任何兼容方法,则忽略在基类中声明的所有签名 – 即使它们在同一派生类中被重写!

换句话说,编译器查看在最派生类中新近声明的方法(基于表达式的编译时类型),并查看是否有任何适用的方法。 如果是,则使用“最佳”可用。 如果不适用,则尝试基类,依此类推。 重写的方法不计为在派生类中声明。

有关详细信息,请参阅C#3规范的7.4.3和7.5.5.1节。

至于为什么它被指定的那样 – 我不知道。 对我来说,在派生类中声明的方法优先于在基类中声明的方法是有意义的,否则你会遇到“脆弱的基类”问题 – 在基类中添加一个方法可能会改变代码的含义使用派生类。 但是,如果派生类重写了基类中声明的方法,那么它清楚地意识到它,因此脆弱元素不适用。

它围绕着范围。 在第一个程序中,void Foo(int i)属于Base类。 class Derived只是重新定义了它的行为。

Foo(int i)被忽略,因为它是“借用”并通过类Base的inheritance重新定义。 如果Foo(对象o)不存在,则使用Foo(int i)。

在第二个程序中,调用void Foo(int i),因为它正确地属于Derived类(即它不被借用并通过inheritance覆盖)并具有最佳签名拟合。

这是因为在考虑基类签名之前,首先匹配派生类中的方法签名。 因此,当你尝试:

 d.Foo(i); 

它尝试将方法签名与当前类(而不是基类)进行匹配。 它找到了一个可接受的匹配Foo(object) ,并没有进一步考虑基类方法签名。

这是关于编译器找到匹配方法签名以及它用于查找这些签名的搜索顺序。

-Doug

真正的问题是为什么C#的设计者认为在这种情况下重载分辨率应该忽略被覆盖的方法?

这样的问题使得方法重载了我最不喜欢的语言function之一。