.Net继承和方法重载

Nic*_* P. 10 .net c# inheritance overloading

这是一个代码示例:

class Program
{
    static void Main(string[] args)
    {
        var obj = new DerivedClass();
        obj.SomeMethod(5);
    }
}

class BaseClass
{
    internal void SomeMethod(int a) { }
}

class DerivedClass : BaseClass
{
    internal void SomeMethod(long a) { }
}
Run Code Online (Sandbox Code Playgroud)

有人可以解释一下为什么派生类调用的方法(而不是基类方法)?我需要详细解释这种情况.我将非常感谢任何有用文章的链接.

谢谢.

Jon*_*nna 21

精确的措辞和位置因规范的不同版本而异,但是例如这里可以读取:

构造了方法调用的候选方法集.从与先前成员查找(第7.3节)找到的与M关联的方法集开始,该集合被简化为适用于参数列表A的那些方法.集合缩减包括应用以下规则集合中的每个方法TN,其中T是声明方法N的类型:

如果N不适用于A(§7.4.2.1),则从集合中删除N.

如果N适用于A(§7.4.2.1),则从集合中删除在基本类型T中声明的所有方法.

因此,假设我们有obj类型,DerivedClass那么成员方法集包含void SomeMethod(long)from DerivedClassvoid SomeMethod(int)from BaseClass.

这两种方法都适用,实际上void SomeMethod(int)是一种更好的重载匹配,但由于上面引用的最后一句中的规则,一旦发现它void SomeMethod(long)是适用的,基类中的所有方法都从候选集中删除,这意味着void SomeMethod(int)不再考虑.

好的,这是规范方面的技术原因.首先是在规范中背后的设计原因是什么?

嗯,想象一下BaseClass开始定义为:

public class BaseClass
{
}
Run Code Online (Sandbox Code Playgroud)

如果代码的其余部分是相同的,那么很明显调用obj.SomeMethod(5)应该调用唯一存在的命名方法.

现在考虑是否编写代码之后,该方法void SomeMethod(int)被添加到BaseClass.并且考虑到这可能是一个不同的集合DerivedClass,并由一个单独的作者.

现在调用的意义SomeMethod()已经改变了.更糟糕的是,它的改变与否取决于给定机器已应用或未应用的更新.(更糟糕的是,由于返回类型未在C#重载决策中使用,因此它的更改方式可能会在已编译的代码中产生编译错误:完全中断更改).

如果存在来自更派生类的重载候选者,则排除基类中定义的方法的规则允许更好地保证在面对未来的更改时调用方法调用方法.(当然,如果您打算调用基类方法,您可能会感到惊讶,但在编码时您可以捕获该问题并使用强制转换来确保您想要的行为是由此产生的).

这种情况的结果可能令人惊讶,但是:

class Program
{
    static void Main(string[] args)
    {
        var obj = new DerivedClass();
        obj.SomeMethod(5);
    }
}
class BaseClass
{
    public virtual void SomeMethod(int a) { Console.WriteLine("Base"); }
}
class DerivedClass : BaseClass
{
    public override void SomeMethod(int a) { Console.WriteLine("Defined in Base, overriden in Derived"); }
    public void SomeMethod(long a) { Console.WriteLine("Derived"); }
}
Run Code Online (Sandbox Code Playgroud)

这会输出Derived,因为此规则根据声明方法的位置应用,即使存在来自覆盖的实现.

(规则正常工作的另一个原因是,当它被转换为CIL时,调用将包含有关它声明的类的信息.这里的规则是最简单的处理方式.那就是说; 1)类似的逻辑应用于CIL的设计和2)上面使这个CCI的一个功能为C#人工作,而不是一个工作对抗).

  • 很棒的答案!+1 (2认同)