C# 为什么要调用此方法?

C# 为什么要调用此方法?,c#,.net,C#,.net,结果:“派生::Foo(对象o)” 为什么???当编译器试图查找候选方法签名以准备重载时,它会首先查看最派生的类型,并删除仅查看该类中“新声明”签名的重写方法 如果它找到了一个适用的方法,它就不会在继承链上再进一步查找其他签名。在这种情况下,这是违反直觉的(至少与我的直觉相反)。它的设计是为了避免“脆弱的基类”问题,即更改基类会以意外的方式影响其他代码——但当该方法在派生类中被实际重写时,我看不到它的好处。(不可否认,忽略这一点意味着似乎没有任何操作方法能够像您预期的那样安全地移除,而这些操作方

结果:“派生::Foo(对象o)”


为什么???

当编译器试图查找候选方法签名以准备重载时,它会首先查看最派生的类型,并删除仅查看该类中“新声明”签名的重写方法

如果它找到了一个适用的方法,它就不会在继承链上再进一步查找其他签名。在这种情况下,这是违反直觉的(至少与我的直觉相反)。它的设计是为了避免“脆弱的基类”问题,即更改基类会以意外的方式影响其他代码——但当该方法在派生类中被实际重写时,我看不到它的好处。(不可否认,忽略这一点意味着似乎没有任何操作方法能够像您预期的那样安全地移除,而这些操作方法只是为了调用基本实现而重写方法。)

我有一篇关于重载的文章,详细介绍了这种情况和其他一些特殊情况——你可能会发现它很有用。有关更多详细信息,请参见C#规范第7.5.3节


一句话:小心重载,特别是跨越继承边界。

@gunner-One会认为应该调用
Devired.Foo(int)
,而不是
Derived.Foo(object)
。有人可能会假设,给定一组与函数调用匹配的函数重载,不涉及任何类型转换且与参数最匹配的将是调用的类型转换。然而,在本例中,情况似乎并非如此。如果我们在派生类中编写public NEW void Foo(int x)是否会有相同的行为?@Arseny:不会,因为对于编译器而言,它是一个“新”方法签名,因此不会从候选集中删除。它不是重写基方法,而是隐藏它。当然,你会遇到这样的问题,你的代码因为隐藏而不清晰……这相当令人失望。遗憾的是,该语言不要求调用具有最合适参数的方法。@锡安:但正如我所提到的,这会导致不同的问题(脆弱的基类)。基本上这里没有完美的解决方案。我会做一些调整来改变我们实际拥有的东西,但值得注意的是他们试图避免的问题。
using System;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            var a = new Derived();
            int x = 123;
            a.Foo(x);
        }
    }

    public class Base
    {
        public virtual void Foo(int x)
        {
            Console.WriteLine("Base::Foo");
        }
    }

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

        public void Foo(object o)
        {
            Console.WriteLine("Derived::Foo(object o)");
        }
    }
}