c# - CLR 在调用结构的方法时如何工作

标签 c# .net clr value-type il

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

(1) CLR通过堆中a类型指针找到ClassA的类型(该类型已经加载到堆)

(2) 查找类型中的MethodA,如果没有找到,则转到其基类型,直到object类。

可能我的理解不是很准确,但是我觉得基本是正确的(不对的请指正!)。一个简单的结构的问题来了。

struct MyStruct
{
   public void MethodA() { }
}

我有var x = new MyStruct();,它的值在栈上,MyStruct的类型已经加载到堆中。当执行x.MethodA()时,当然没有装箱。 CLR 如何找到 MethodA 并获取 IL 并执行/JIT?我想答案大概是:(再一次,如果我错了请纠正我)

(1) 我们在堆栈上有x声明类型。 CLR通过栈上的信息找到它的类型,在它的类型中找到MethodA。 -- 我们称它为 assumptionA

如果您告诉我我的assumptionA 是正确的,我会很高兴。但即使它是错误的,它也说明了一个事实:CLR 有一种无需装箱即可找到结构类型的方法。

现在 x.ToString()x.GetType() 呢?我们知道这个值会被装箱,然后它会像一个类一样执行。但是为什么我们在这里需要拳击呢?既然我们可以得到它的类型(假设A告诉我们),为什么不去它的基类型找到方法(就像一个类)?为什么这里需要昂贵的盒子操作?

最佳答案

假设 A 是错误的。 C# 编译器的符号表存储类型信息。几乎所有情况下都使用静态类型信息,存储在对象中的动态类型仅在类型检查(is 运算符)、转换(as 运算符)和实际转换时需要语法)和数组变体,然后仅当编译器不知道动态类型时。未装箱结构的动态类型始终是静态已知的,并且类实例的动态类型在实例化附近和执行类型检查的条件 block 内是静态已知的(例如,在 if (x is T) y = ( T)x; 该类型在 then 部分内是已知的,因此转换不需要另一次动态检查)。

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

对于 x.ToString(),C# 编译器仍然知道它要调用的确切方法。如果 ToString 已被 struct 类型覆盖,它需要一个 pointer-to-MyStruct 类型的参数,编译器无需装箱即可处理。如果未覆盖 ToString,编译器将生成对 Object.ToString 的调用,它需要一个对象作为其参数。将 x 作为正确的类型推送到 MSIL 虚拟堆栈上需要装箱。

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

关于c# - CLR 在调用结构的方法时如何工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5494807/

相关文章:

c# - .NET 4.0 协方差

c# - 应用程序调用了为不同线程编码的接口(interface) - Windows 应用商店应用程序

c# - linq join 3 tables with or condition

项目之间的c++ header

.net - 方法名称中的连字符,是否可以在任何 .NET 语言中使用?

c# - 如何从 FIFO 队列中返回最新的对象而不删除它

c# - 使用 C# 加密 PDF 文档

.net - 子串长度

c# - 上下移动 ListViewItems

.net - callvirt 在底层是如何工作的?