(1)CLR通过堆中a的类型指针找到ClassA的类型(该类型已加载到堆中)
(2)在类型中找到MethodA,如果找不到,则转到其基类型,直到对象类.
也许我的理解不太准确,但我认为这是基本正确的(纠正我,如果它是错的!).这是一个简单结构的问题.
struct MyStruct { public void MethodA() { } }
我有var x = new MyStruct();,它的值在堆栈上,并且MyStruct的类型已经加载到堆中.当执行x.MethodA()时,当然没有拳击. CLR如何找到MethodA并获取IL并执行/ JIT呢?我想答案可能是:(再次,如果我错了,请纠正我)
(1)我们在堆栈上有x的声明类型. CLR通过堆栈上的信息找到它的类型,并在其类型中找到MethodA. – 让我们称之为假设A.
如果你告诉我我的假设是正确的,我会很高兴的.但即使它是错的,它也说明了一个事实:CLR有一种方法可以在没有装箱的情况下找到结构类型.
那么x.ToString()或x.GetType()呢?我们知道该值将被加框,然后它将像一个类一样执行.但为什么我们需要拳击呢?既然我们可以得到它的类型(假设A告诉我们),为什么不去它的基类型并找到方法(就像一个类)?为什么这里需要昂贵的箱子操作?
解决方法
好的,现在因为C#编译器静态地知道x的类型,它可以进行重载解析并找到被调用的精确MethodA.然后它发出MSIL以将参数推送到MSIL虚拟堆栈并发出包含对该特定方法的元数据引用的调用指令.运行时不需要进行类型检查.
对于x.ToString(),C#编译器仍然知道它想要调用的确切方法.如果ToString已被结构类型覆盖,则它需要一个类型为pointer-to-MyStruct的参数,编译器在没有装箱的情况下处理该参数.如果尚未覆盖ToString,则编译器会生成对Object.ToString的调用,该调用期望将对象作为其参数.要在MSIL虚拟堆栈上按x,因为正确的类型需要装箱.
GetType是一种特殊情况,当静态地知道类型时,编译器不会调用任何方法,它只是从符号表中获取类型信息并直接将元数据引用填充到MSIL中.