1
class Program
{
    static void Main(string[] args)
    {
        B foo = new B();
        foo.DoWork();
        Console.ReadLine();
    }
}

public class A
{
    public virtual void DoWork() { Console.WriteLine("A"); }
}
public class B : A
{
    public override void DoWork() { base.DoWork();  Console.WriteLine("B"); }
}

为什么我没有得到 StackOverflow 异常?据我了解,调用 foo.DoWork(),然后调用 base.DoWork(),它是虚拟的并在类 B.DoWork() 方法中被覆盖,它将再次重复调用 base.DoWork(),直到堆栈溢出. 当使用 this 而不是 base(调用 self 的循环循环)时,很容易实现这种溢出。在这种情况下,是什么阻止了虚函数覆盖?

4

3 回答 3

11

不,当您使用base它时,它不会进行虚拟通话。重点是即使您已经覆盖base了实现,也能够调用它。

如果您查看生成的 IL,您会发现它没有使用callvirt

IL_0002:  call       instance void A::DoWork()

从 C# 5 规范的第 7.6.8 节(强调我的):

当基本访问引用虚拟函数成员(方法、属性或索引器)时,在运行时(第 7.5.4 节)调用哪个函数成员的确定会改变。被调用的函数成员是通过查找函数成员相对于 B 的最派生实现(第 10.6.3 节)来确定的(而不是相对于 this 的运行时类型,这在非基础访问)。因此,在虚函数成员的覆盖中,可以使用基本访问来调用函数成员的继承实现。如果基本访问引用的函数成员是抽象的,则会发生绑定时错误。

于 2013-01-24T22:08:22.637 回答
2

A.DoWork是虚拟的。但是名为 by 的方法base.永远不是虚拟的。该语法会生成一个非虚拟调用,因此调用的是确切的方法,而不是最派生的版本。

于 2013-01-24T22:08:27.920 回答
1

虚拟方法只是一种可以被覆盖并且包含代码的方法。当你打电话时,base.DoWork()你明确声明你想打电话A.DoWork()。然后,A.DoWork()被调用。

尝试制作A.DoWork()抽象然后它不能包含代码。然后,您将遇到编译错误,base.DoWork()因为在base.DoWork().

于 2013-01-24T22:08:17.783 回答