我试图了解从Essential C#6.0(MarkMichaelis和EricLippert)进行方法调用时拳击/拆箱的影响,最终比我开始时更加困惑。
以下是本书的代码:
struct A
{
public int Val {get; set;};
//doesn't override ToString
}
A vo = new A();;
object thing;
// Boxing
thing = vo;
string text = ((A)thing).ToString();
Console.WriteLine(text);
作者接着说:
如果接收器未装箱且结构未覆盖 ToString(),必须调用基类实现,并且它 期望引用对象作为其接收者。因此, 接收器是盒装的。
在上面的代码中就是这种情况,其中对A的强制转换运算符将取消装入'thing',然后尝试在临时上调用ToString。由于ToString()方法尚未在结构A中被覆盖,因此只有在再次装入由强制转换(A)生成的临时值或者编译器完全优化取消装箱/装箱后,才会发生对ToString的调用。
但是生成的CIL如下所示,确实表明'thing'已经被取消装箱,但是对ToString()的调用没有被重新装箱。请帮我理解这一点。
.locals init (valuetype Chapter7.A V_0,
object V_1,
string V_2,
valuetype Chapter7.A V_3)
IL_0000: nop
IL_0001: ldloca.s V_0
IL_0003: initobj Chapter7.A
IL_0009: ldloc.0
**IL_000a: box Chapter7.A** //thing = vo
IL_000f: stloc.1
IL_0010: ldloc.1
**IL_0011: unbox.any Chapter7.A** //((A)thing)
IL_0016: stloc.3
IL_0017: ldloca.s V_3 //the temporary where unboxed value is stored
IL_0019: constrained. Chapter7.A
IL_001f: callvirt instance string [mscorlib]System.Object::ToString()