Я эта статья MSDN Magazine, состояния автора (шахта акцента):
Обратите внимание, что упаковка всегда создает новый объект и копирует биты распакованного значения в объект. С другой стороны, распаковывание просто возвращает указатель на данные в помещенном в коробку объекте: никакая копия памяти не происходит. Однако обычно имеет место, что Ваш код заставит данные, на которые указывает распакованная ссылка быть скопированными так или иначе.
Я смущен предложением, которое я имею полужирный и предложение, которое следует за ним. От всего остального я читал, включая эту страницу MSDN, я прежде никогда не слышал, что распаковывание просто возвращает указатель на значение на "куче". У меня создалось впечатление, что распаковывание приведет к Вам имеющий переменную, содержащую копию значения на стеке, когда Вы начали. В конце концов, если моя переменная содержит "указатель на значение на "куче"", затем у меня нет типа значения, у меня есть указатель.
Кто-то может объяснить, что это означает? Был автор на трещине? (Существует по крайней мере еще одна явная ошибка в статье). И если это верно, каковы случаи, где "Ваш код заставит данные, на которые указывает распакованная ссылка быть скопированными так или иначе"?
Я просто заметил, что статье почти 10 лет, поэтому возможно, это - что-то, что изменилось очень вначале в жизни .NET.
Статья точная. Однако в ней говорится о том, что действительно происходит, а не о том, как выглядит IL, который генерирует компилятор. В конце концов, программа .NET никогда не выполняет IL, она выполняет машинный код, который генерируется из IL компилятором JIT.
И опкод unbox действительно генерирует код, который производит указатель на биты на куче, представляющие значение типа value. JIT генерирует вызов небольшой вспомогательной функции в CLR с именем "JIT_Unbox". clr\src\vm\jithelpers.cpp, если вы получили исходный код SSCLI20. Функция Object::GetData() возвращает указатель.
Оттуда значение чаще всего сначала копируется в регистр процессора. Затем оно может где-то храниться. Это не обязательно должен быть стек, это может быть член объекта ссылочного типа (куча gc). Или статическая переменная (куча загрузчика). Или она может быть помещена в стек (вызов метода). Или регистр процессора может быть использован как есть, когда значение используется в выражении.
Во время отладки щелкните правой кнопкой мыши на окне редактора и выберите "Go To Disassembly", чтобы увидеть машинный код.
Боксирование - это акт приведения экземпляра типа значения к экземпляру типа ссылки (либо объекту
, либо интерфейсу), а ссылочные типы размещаются на куче.
Согласно "C# 4.0 in a Nutshell": " ... unboxing copies содержимое объекта обратно в экземпляр типа значения", а это подразумевает выделение на стеке.
В статье, на которую вы ссылаетесь, автор утверждает:
public static void Main() {
Int32 v = 5; // Create an unboxed value type variable
Object o = v; // o refers to a boxed version of v
v = 123; // Changes the unboxed value to 123
Console.WriteLine(v + ", " + (Int32) o); // Displays "123, 5"
}
Из этого кода вы можете угадать, сколько операций боксирования? Возможно, вы будете удивитесь, узнав, что ответ три! Давайте проанализируем код внимательно, чтобы понять, что что происходит. Во-первых, создается тип значения Int32 без коробки (v), который инициализируется значением 5. Затем создается ссылочный тип Object (o), который хочет указать на v. Но ссылочные типы всегда должны указывать на объекты в куче, поэтому C# сгенерировал соответствующий IL-код, чтобы поместить v и сохранил адрес упакованной версии v в o. Теперь 123 распаковывается и данные по ссылке копируются в небоксовый тип значения v; это не имеет никакого не влияет на ящичную версию v, поэтому ящичная версия сохраняет свое значение 5. Обратите внимание, что в этом примере показано, как o раскрывается (что возвращает указатель на данные в o), а затем данные в o копируются в память для сохранения в распакованном значении type v.