【问题标题】:How CLR calls methods correctly hidden by derived class when reference is stored in a base class variable?当引用存储在基类变量中时,CLR 如何正确调用派生类隐藏的方法?
【发布时间】:2012-08-18 09:41:56
【问题描述】:

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

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

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

【问题讨论】:

    标签: .net clr


    【解决方案1】:

    对象头中记录的对象类型在这里无关紧要。编译器发出方法调用,命名应调用其方法的特定类。在生成的 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的存在,没有歧义。

    【讨论】:

    • 我查看了 IL,但由于某种原因,我认为 CLR 始终会查询方法表。这是有道理的,方法表仅用于调度虚拟方法调用,即如果方法无法在编译时确定。如果需要调用的方法可以在编译时确定,则无需查看方法表。谢谢你。
    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-28
      • 1970-01-01
      • 1970-01-01
      • 2011-05-11
      • 2014-09-05
      • 1970-01-01
      • 1970-01-01
      • 2013-04-11
      相关资源
      最近更新 更多