我试图了解当对象引用存储在基类变量中时,当对象隐藏基类成员时,CLR如何正确调用方法。
我的困惑之处在于运行时创建的对象标头。堆上的对象头有两个字段:类型指针和同步块索引。类型指针指向类的方法表。即使对象引用是基类,在堆上创建的对象也是派生类。这应该导致运行时使用派生类对象的方法表。但运行时正确调用基类成员。
在这种情况下,CLR如何正确调用方法,请您帮助我理解流程?
答案 0 :(得分:4)
对象标题中记录的对象类型在此处无关紧要。编译器发出方法调用,命名应该调用其方法的特定类。在生成的IL中非常明显。例如:
class Base {
void foo() { }
void callFoo() {
foo(); // <== here
}
}
class Derived : Base {
new void foo() { }
}
指示的语句生成此IL:
IL_0002: call instance void ConsoleApplication1.Base::foo()
注意在调用操作码中存在Base,没有歧义。
答案 1 :(得分:1)
调用非虚拟或以任何方式覆盖的方法与方法表无关。 C#编译器按名称调用该方法(程序集实际上包含名称作为字符串!),JIT将函数的地址硬编码到发出的x86代码中。该地址不依赖于this
对象引用的运行时类型。