.net 当引用存储在基类变量中时,CLR如何调用派生类正确隐藏的方法?

.net 当引用存储在基类变量中时,CLR如何调用派生类正确隐藏的方法?,.net,clr,.net,Clr,我试图理解当对象引用存储在基类变量中时,当对象隐藏基类成员时,CLR如何正确地分派方法调用 我感到困惑的是运行时创建的对象头。堆上的对象头有两个字段:类型指针和同步块索引。类型指针指向类的方法表。即使对象引用是基类,在堆上创建的对象也是派生类。这将导致运行时使用派生类对象的方法表。但是运行时正确地调用基类成员 您能帮助我理解流程吗?在这种情况下,CLR如何正确地调用方法?对象标题中记录的对象类型在这里并不重要。编译器发出方法调用,命名应调用其方法的特定类。在生成的IL中非常可见。例如: clas

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

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


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

对象标题中记录的对象类型在这里并不重要。编译器发出方法调用,命名应调用其方法的特定类。在生成的IL中非常可见。例如:

class Base {
    void foo() { }
    void callFoo() {
        foo();         // <== here
    }
}
class Derived : Base {
    new void foo() { }
}

请注意,在调用操作码中存在Base,因此没有歧义。

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

我查看了IL,但出于某种原因,认为CLR总是查阅方法表。这意味着只有在编译时无法确定方法的情况下,才会在分派虚拟方法调用时参考方法表。若需要调用的方法可以在编译时确定,那个么就不需要查看方法表。谢谢你。
IL_0002:  call       instance void ConsoleApplication1.Base::foo()