4

我试图了解当对象引用存储在基类变量中时对象隐藏基类成员时,CLR 如何正确调度方法调用。

我的困惑点是运行时创建的对象头。堆上的对象头有两个字段:类型指针和同步块索引。类型指针指向类的方法表。即使对象引用是基类的,在堆上创建的对象也是派生类的。这应该导致运行时使用派生类对象的方法表。但是运行时正确地调用了基类成员。

您能否帮助我理解流程,因为 CLR 在这种情况下如何正确调用方法?

4

2 回答 2

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 的存在,没有歧义。

于 2012-08-18T10:06:34.523 回答
1

调用非虚拟或以任何方式覆盖的方法与方法表无关。C# 编译器按名称调用该方法(程序集确实包含作为字符串的名称!)并且 JIT 将函数的地址硬编码到发出的 x86 代码中。地址不依赖于this对象引用的运行时类型。

于 2012-08-18T10:09:35.593 回答