.Net继承和方法重载 [英] .Net inheritance and method overloading

查看:170
本文介绍了.Net继承和方法重载的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下是代码示例:

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) { }
}

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

Can somebody explain me why is a method from derived class called (instead of base class method)? I need a detailed explanation for this situation. I will be grateful for links to any useful articles.

谢谢。

推荐答案

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

The precise wording and location varies with different versions of the spec, but for example here one can read:


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

The set of candidate methods for the method invocation is constructed. Starting with the set of methods associated with M, which were found by a previous member lookup (§7.3), the set is reduced to those methods that are applicable with respect to the argument list A. The set reduction consists of applying the following rules to each method T.N in the set, where T is the type in which the method N is declared:

如果N不适用于A(第7.4.2.1节) ),然后从集合中移除N.

If N is not applicable with respect to A (§7.4.2.1), then N is removed from the set.

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

If N is applicable with respect to A (§7.4.2.1), then all methods declared in a base type of T are removed from the set.

因此,我们有 obj 键入 DerivedClass 然后成员方法集包含 void SomeMethod(long) from DerivedClass void SomeMethod(int) from BaseClass

So, given that we have obj of type DerivedClass then the set of member methods contains void SomeMethod(long) from DerivedClass and void SomeMethod(int) from BaseClass.

这两种方法都适用,实际上 void SomeMethod(int)是一个更好的overloa d匹配,但由于上面引用的最后一句中的规则,一旦发现 void SomeMethod(long)适用,基类中的所有方法都将从一组候选人,意思是 void SomeMethod(int)不再被考虑。

Both of these methods are applicable, and indeed void SomeMethod(int) is a better overload match, but because of the rule in the last sentence quoted above, once it is found that void SomeMethod(long) is applicable, all methods from base classes are removed from the set of candidates, meaning that void SomeMethod(int) is no longer considered.

好的,这是技术原因就规格而言。首先出现在规范背后的设计原因是什么?

Okay, that's the technical reason in terms of the spec. What is the design reason behind that being in the spec in the first place?

好吧,想象一下 BaseClass 开始了out定义为:

Well, imagine that BaseClass started out defined as:

public class BaseClass
{
}

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

If the rest of the code was the same, then it's pretty obvious that the call to obj.SomeMethod(5) should call the only so-named method that existed.

现在考虑是否 后写了代码,方法 void SomeMethod(int)已添加到 BaseClass 。并且考虑到这可能是与 DerivedClass 的不同程序集,以及另一位作者。

Now consider if after that code was written, the method void SomeMethod(int) was added to BaseClass. And consider indeed that this could be in a different assembly to DerivedClass, and by a separate author.

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

Now the meaning of the call to SomeMethod() has changed. Worse, it's changed or not depending on which updates a given machine has or hasn't got applied. (And worse again, since return type isn't used in C# overload resolution, it's changed in a way that could produce a compile error in already-compiled code: A full breaking change).

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

The rule of excluding methods defined in a base class if there are overload candidates from a more derived class allows for greater assurance that one is calling the method one intended to call, in the face of future changes. (Of course you might be surprised if you'd intended the base classes methods to be called, but then at the time of coding you could catch that problem and use a cast to ensure the behaviour you wanted was what resulted).

这样做的后果可能令人惊讶,但是:

A consequence of this that can be surprising to some though is in:

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"); }
}

此输出派生,因为此规则根据声明方法的位置应用,即使存在覆盖的实现。

This outputs Derived, because this rule applies according to where the method is declared, even if there is an implementation from an override.

(规则正常工作的另一个原因,当它被转换成CIL时,调用将包含有关它所声明的类的信息。这里的规则是最简单的处理方式。那就是说:1)在CIL的设计中应用了类似的逻辑,2)以上这使得C#的一个功能可以让C#人员使用,而不是一个人工作。

(Another reason for the rule working as it does, is that when it's converted into CIL the call will contain information about the class it's declared in. The rule here is the simplest possible way of doing things. That said; 1) A similar logic applied in the design of CIL and 2) the above made this a feature of CIL for the C# people to work with, rather than one to work against).

这篇关于.Net继承和方法重载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆