Значения типа значения для класса имеют для совместного использования с экземпляром объекта в управляемой куче. Стек потока для метода живет только в течение срока действия метода; как значение может сохраняться, если оно существует только в этом стеке?
Размер объекта класса в управляемой куче является суммой его полей типа значения, указателей ссылочного типа и дополнительных служебных переменных CLR, таких как индекс блока Sync. Когда кто-либо присваивает значение полю типа значения объекта, CLR копирует это значение в пространство, выделенное в объекте для этого конкретного поля.
Возьмем, к примеру, простой класс с одним полем.
public class EmbeddedValues
{
public int NumberField;
}
А с ним и простой класс тестирования.
public class EmbeddedTest
{
public void TestEmbeddedValues()
{
EmbeddedValues valueContainer = new EmbeddedValues();
valueContainer.NumberField = 20;
int publicField = valueContainer.NumberField;
}
}
Если вы используете дизассемблер MSIL, предоставляемый .NET Framework SDK, для просмотра кода IL для EmbeddedTest.TestEmbeddedValues ()
.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 сообщается stfld загруженному значению "20" в стеке к расположению поля NumberField загруженного EmbeddValues непосредственно в управляемую кучу. Аналогично, при извлечении значения он использует инструкцию ldfld , чтобы напрямую скопировать значение из этого расположения управляемой кучи в стек потока. С этими типами операций не происходит коробка / распаковка.