微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

c# – 调用struct的方法时CLR的工作原理

我想我已经知道了一堂课的答案,只想确认我的理解是正确的.假设我有一个ClassA,它的实例名为a.当调用a.MethodA()时:

(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告诉我们),为什么不去它的基类型并找到方法(就像一个类)?为什么这里需要昂贵的箱子操作?

解决方法

AssumptionA错了. C#编译器的符号表存储类型信息.几乎在所有情况下都使用静态类型信息,只有在类型检查(运算符),转换(作为运算符和实际转换语法)和数组方差时才需要存储在对象中的动态类型,然后仅在动态类型时使用编译器不知道.未装箱结构的动态类型始终是静态已知的,并且类实例的动态类型在实例化附近和执行类型检查的条件块内是静态已知的(例如,在if(x是T)y =(T)x ;类型在then-part中是已知的,因此强制转换不需要另外的动态检查).

好的,现在因为C#编译器静态地知道x的类型,它可以进行重载解析并找到被调用的精确MethodA.然后它发出MSIL以将参数推送到MSIL虚拟堆栈并发出包含对该特定方法的元数据引用的调用指令.运行时不需要进行类型检查.

对于x.ToString(),C#编译器仍然知道它想要调用的确切方法.如果ToString已被结构类型覆盖,则它需要一个类型为pointer-to-MyStruct的参数,编译器在没有装箱的情况下处理该参数.如果尚未覆盖ToString,则编译器会生成对Object.ToString的调用,该调用期望将对象作为其参数.要在MSIL虚拟堆栈上按x,因为正确的类型需要装箱.

GetType是一种特殊情况,当静态地知道类型时,编译器不会调用任何方法,它只是从符号表中获取类型信息并直接将元数据引用填充到MSIL中.

原文地址:https://www.jb51.cc/csharp/244063.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐