【发布时间】:2021-05-01 21:03:57
【问题描述】:
假设我们有以下 C# 代码:
public static void Main()
{
int v = 5;
Object o = v;
v = 123;
Console.WriteLine(v + (Int32) o); // Displays "1235"
}
而生成的IL代码是:
.locals init ([0]int32 v, [1] object o)
// Load 5 into v.
IL_0000: ldc.i4.5
IL_0001: stloc.0
// Box v and store the reference pointer in o. <------first boxing
IL_0002: ldloc.0
IL_0003: box [mscorlib]System.Int32
IL_0008: stloc.1
// Load 123 into v.
IL_0009: ldc.i4.s 123
IL_000b: stloc.0
// Box v and leave the pointer on the stack for Concat. <------second boxing
IL_000c: ldloc.0
IL_000d: box [mscorlib]System.Int32
// Unbox o: Get the pointer to the In32's field on the stack.
IL_0017: ldloc.1
IL_0018: unbox.any [mscorlib]System.Int32
// Box the Int32 and leave the pointer on the stack for Concat. <------third boxing
IL_001d: box [mscorlib]System.Int32
// Call Concat.
IL_0022: call string [mscorlib]System.String::Concat(object, object)
我们可以看到第一次拳击和第二次拳击的工作原理如下:
-
将第一个参数
v推入堆栈。 -
致电
boxCIL
所以看起来当box被调用时,需要的“参数”是指向v的第一个字段的堆栈指针。
第三拳的作用如下:
-
前面的
unbox创建了一个值类型指针,这个值类型指针指向堆上装箱实例的第一个字段,然后这个值类型指针被压入栈中。 -
致电
boxCIL
所以现在看起来当box被调用时,它首先检查堆栈指针以通过取消引用堆栈指针来获取其内容(指向堆的值类型指针)。
所以我的问题是,box CIL 是否被设计成通用的,有时它直接读取堆栈指针,而有时它取消引用堆栈指针以获取另一个指针(在我的情况下是指向堆的指针)?
【问题讨论】:
-
注意有很好的回复here