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

5
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(object),请帮助我理解这两者的区别。

1
"近在咫尺胜于远方。"编译器更喜欢派生类中首先声明的方法,即对象重载。了解更多信息:http://ericlippert.com/2013/12/23/closer-is-better/#more-1806 - Anthony Pegram
2个回答

7
很好的问题,我可以重现你的结果。如果查看C# 规范,将会发现以下片段:
7.5.3 重载决策
例如,方法调用的候选集不包括标记为override (§7.4) 的方法,并且如果派生类中的任何方法适用,则基类中的方法不是候选项 (§7.6.5.1)。
7.4 成员查找
否则,集合包括 T 中所有命名为 N 的可访问成员 (§3.5),包括继承的成员和 object 中命名为 N 的可访问成员。如果 T 是构造类型,则成员集合是通过按 §10.3.2 中所述替换类型参数来获得的。该集合排除了包括override修饰符的成员。
7.6.5.1 方法调用
候选方法集被缩小为仅包含最派生类型中的方法:对于集合中的每个 C.F 方法,其中 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之后才考虑这一点。正如Eric Lippert(其中一位设计师)所说:越近越好。 (感谢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)");
    }
}

尽管具体细节最好留待另一个问题来解决!

0
简单数据类型int源自object。您正在重写函数,同时也在重载参数列表。由于函数名相同但签名不同,编译器允许这样做。对于简单对象,我想最基本形式的参数签名副本被存储在方法表中。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接