类的值类型值必须与托管堆中的对象实例一起存在。方法的线程堆栈仅在方法的持续时间内存在;如果该值仅存在于该堆栈中,它如何持续存在?
托管堆中类的对象大小是其值类型字段、引用类型指针和其他 CLR 开销变量(如同步块索引)的总和。当为对象的值类型字段赋值时,CLR 会将值复制到对象内为该特定字段分配的空间中。
以一个具有单个字段的简单类为例。
public class EmbeddedValues
{
public int NumberField;
}
有了它,一个简单的测试类。
public class EmbeddedTest
{
public void TestEmbeddedValues()
{
EmbeddedValues valueContainer = new EmbeddedValues();
valueContainer.NumberField = 20;
int publicField = valueContainer.NumberField;
}
}
如果您使用 .NET Framework SDK 提供的 MSIL Disassembler 查看 EmbeddedTest.TestEmbeddedValues() 的 IL 代码
.method public hidebysig instance void TestEmbeddedValues() cil managed
{
// Code size 23 (0x17)
.maxstack 2
.locals init ([0] class soapextensions.EmbeddedValues valueContainer,
[1] int32 publicField)
IL_0000: nop
IL_0001: newobj instance void soapextensions.EmbeddedValues::.ctor()
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: ldc.i4.s 20
IL_000a: stfld int32 soapextensions.EmbeddedValues::NumberField
IL_000f: ldloc.0
IL_0010: ldfld int32 soapextensions.EmbeddedValues::NumberField
IL_0015: stloc.1
IL_0016: ret
} // end of method EmbeddedTest::TestEmbeddedValues
请注意,CLR 被告知将堆栈中加载的“20”值直接存储到托管堆中加载的 EmbeddValues 的 NumberField 字段位置。同样,在检索值时,它使用ldfld指令直接将值从托管堆位置复制到线程堆栈中。这些类型的操作不会发生装箱/拆箱。