具有重写的 C# 重载

本文关键字:重载 重写 | 更新日期: 2023-09-27 18:35:56

我当然可以通过自己编写虚拟测试来回答这个问题,但我想知道人们对这个问题的看法。在这里:

当我们同时进行重载和覆盖时,将调用哪个方法?我只考虑类型重载而不是 arity 重载以及当类型重载相关时。

我举个例子:

class AA {}
class BB : AA {}
class A {
    public virtual void methodA(AA anAA) { Console.Write("A:methodA(AA) called"); }
    public virtual void methodA(BB aBB) { Console.Write("A:methodA(BB) called"); }
}
class B : A {
    public override void methodA(AA anAA) { Console.Write("B:methodA(AA) called"); }
}
new B().methodA(new BB());     // Case 1
new B().methodA(new AA());     // Case 2
new B().methodA((AA)new BB()); // Case 3

你能说出在案例 1、2 和 3 中会发生什么吗?

我个人认为超载是邪恶的,没有一致的思维可以导致可预测的答案。这完全基于编译器+vm中实现的约定。

编辑:如果你对为什么过载是邪恶的有一些疑问,你可以阅读吉拉德布拉赫的博客文章

谢谢

具有重写的 C# 重载

不,这是完全可以预测的。首先解析方法签名 - 即首先确定重载。然后,调用最重写的方法。所以输出将是:

    A
  • :方法A(BB) 调用
  • B:方法A(AA) 调用
  • B:方法A(AA) 调用

在后两种情况下,将调用采用 AA 实例的方法,因为这是传入的引用的类型,并且调用的是 B 的版本。请注意,即使这样也会产生相同的结果:

A instance = new B();
instance.methodA((AA)new BB()); // Case 3

当编译器确定要调用的方法时,重写的方法将从方法集中排除。请参阅成员查找算法。因此,当您在类型 B 上调用 methodA 时,将构造一组名称为 methodA 来自类型 B 的成员及其基类型:

override B.methodA(AA)
virtual A.methodA(AA)
virtual A.methodA(BB)

然后从集合中删除了ovveride修饰符的成员:

virtual A.methodA(AA)
virtual A.methodA(BB)

这组方法是查找的结果。之后,应用重载解析来定义要调用的成员。

  1. A.methodA(BB)被调用,因为它的参数与参数匹配。
  2. A.methodA(AA)将被选中,但它是虚拟方法,因此实际上调用会转到B.method(AA)
  3. 与选项 2 相同
我认为

结果将是这样的

案例 1 : Console.Write("A:methodA(BB) called");

案例 2 : Console.Write("B:methodA(AA) called");

案例 3 : Console.Write("B:methodA(AA) called");

在情况 3 中,它看起来是它传递的类型,它是 B