我试图了解继承在C#中的工作方式。我写了以下代码:

class Program
{
    static void Main(string[] args)
    {
        Animal animal = new Dog();
        animal.OverRideMe();
        //animal.NewMethod();
        Dog dog = (Dog)animal;
        dog.OverRideMe();
        dog.NewMethod();
        Console.Read();
    }
}
public abstract class Animal
{
    public Animal()
    {
        Console.WriteLine("Base Constructor");
    }
    public virtual void OverRideMe()
    {
        Console.WriteLine("In Base Class's OverRideMe");
        Console.Read();
    }
}
public class Dog : Animal
{
    public Dog()
    {
        Console.WriteLine("Derived Constructor");
    }
    public override void OverRideMe()
    {
        Console.WriteLine("In Derived Class's OverRideMe");
        Console.Read();
    }
    public void NewMethod()
    {
        Console.WriteLine("In Derived Class's NewMethod");
        Console.Read();
    }
}

Main()的CIL(通用中间语言)代码如下所示:
.method private hidebysig static
    void Main (
        string[] args
    ) cil managed
{
    // Method begins at RVA 0x2050
    // Code size 42 (0x2a)
    .maxstack 1
    .entrypoint
    .locals init (
        [0] class ConsoleApplication1.Animal animal,
        [1] class ConsoleApplication1.Dog dog
    )

    IL_0000: nop
    IL_0001: newobj instance void ConsoleApplication1.Dog::.ctor()
    IL_0006: stloc.0
    IL_0007: ldloc.0
    IL_0008: callvirt instance void ConsoleApplication1.Animal::OverRideMe()
    IL_000d: nop
    IL_000e: ldloc.0
    IL_000f: castclass ConsoleApplication1.Dog
    IL_0014: stloc.1
    IL_0015: ldloc.1
    IL_0016: callvirt instance void ConsoleApplication1.Animal::OverRideMe()
    IL_001b: nop
    IL_001c: ldloc.1
    IL_001d: callvirt instance void ConsoleApplication1.Dog::NewMethod()
    IL_0022: nop
    IL_0023: call int32 [mscorlib]System.Console::Read()
    IL_0028: pop
    IL_0029: ret
} // end of method Program::Main

CIL中令我困扰的几行是:
IL_000f: castclass ConsoleApplication1.Dog
IL_0014: stloc.1
IL_0015: ldloc.1
IL_0016: callvirt instance void ConsoleApplication1.Animal::OverRideMe()
IL_001b: nop
IL_001c: ldloc.1
IL_001d: callvirt instance void ConsoleApplication1.Dog::NewMethod()

在将动物转换类转换为 Dog 后,该代码将执行 dog.OverRideMe(); 。这被翻译成CIL



我已经将动物对象转换为类型。为什么要 dog.OverRideMe(); 是否可以在CIL中翻译成上述声明?上面代码的输出是:

此输出与基类动物无关,但CIL仍对其进行调用。

最佳答案

您正在调用虚拟方法。虚方法的调用由对象的运行时类型确定。您可以将其称为Dog,但编译器仍将发出指令,以确定在运行时调用的适当方法。从dog的编译时类型开始,它沿继承链向上移动,直到找到OverRideMe的“顶级”定义1,并为此发出虚拟方法调用。在这种情况下,OverRideMe定义在继承链中的最高位置是Animal;因此,它为Animal.OverRideMe发出虚拟方法调用。

这是一个previous answer,可以帮助您更好地了解正在发生的事情。

1:在继承链中定义方法的最高位置。这里必须格外小心,以了解方法隐藏的方式以及哪些因素不会对此产生影响。

10-06 03:30