2016-04-04 22 views
4
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)"); 
     } 
    } 
} 

输出应该美孚(INT),但输出来作为美孚(对象),请帮助我理解之探源输出为什么方法重载在这个C#程序中不起作用?根据我的程序

+1

“编译器更喜欢首先在派生类中声明的方法,这是对象重载。更多信息:http://ericlippert.com/2013/12/23/closer-is-better/#more-1806 –

回答

6

好问题,我可以重现你的结果。如果一个需要看看在C#specifications人会发现下面的代码片段:

7.5.3重载决策

例如,对于集合的方法调用的候选并不 包括标记方法覆盖(§7.4),并且基类 中的方法不适用于派生类中的任何方法适用 (第7.6.5.1节)。

7.4成员查找

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

7.6.5.1方法调用

的候选方法集被减少到仅包含从方法 最派生类型:对于组中的每个方法CF,其中C是 声明方法F的类型,在集合中删除在基类 类型C中声明的所有方法。此外,如果C是除对象以外的类型 ,则在接口类型中声明的所有方法都是从该集合中删除的 。

听起来有点复杂?即使是C#设计师似乎这么认为,并把在“有用”注:

7.6.5.1方法调用

上述决议规则的直观效果为 如下:要定位的具体方法通过一种方法 调用调用,启动与由所述方法调用所指示的类型和 继续向上继承链,直到至少一个适用, 访问的,非重写方法声明被发现。然后在该类型中声明的一组适用的,可覆盖的非覆盖方法上执行 类型推断和重载分辨率,并调用如此选择的方法。 如果找不到方法,请尝试将该调用作为扩展方法调用进行处理。

如果我们看一看你的派生类中,我们看到了C#使用两种可能的方法:

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

让我们用这最后的清单!

适用性 - A和B都适用 - (都是无效的,都命名为'Foo',并且都可以接受整数值)。 辅助功能 - A和B都可以访问(公共) 不可覆盖 -只有B不被覆盖。

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

正确的,但考虑到仅仅是由后,我们已经忽略选项A.作为埃里克利珀(设计师之一)所言Closer is always better than farther away.(感谢安东尼Pegram)

附录

总是有the 'new' keyword

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

    public void Foo(object i) 
    { 
     Console.WriteLine("Foo(object)"); 
    } 
} 

虽然最好的具体情况留给另一个问题!

0

简单数据类型int从对象下降。您正在重写该函数,并且还重载了参数列表。由于函数名称与不同的签名相同,编译器允许这样做。对于简单的对象,我以最基本的形式将参数签名的一个副本映像存储在方法表中。 “关闭比远处更好”

相关问题