Разработчики .NET Framework могли бы сделать все типы ссылочными, но они предпочли поддерживать еще и размерные типы, чтобы избежать неоправданных издержек при использовании целых чисел и других элементарных типов данных.
Однако такое «раздвоение личности» системы типов повлекло за собой и неприятности. Чтобы передать размерный тип методу, ожидающему ссылочный тип, нужно преобразовать размерный тип в ссылочный, По сути преобразовать размерный тип в ссылочный нельзя, зато можно упаковать (box) размерный тип. При упаковке в управляемой куче создается копия размерного типа. Процесс, обратный упаковке, называется распаковкой (unboxing). При этом в С# дубликат ссылочного типа помещается в стек. В общем промежуточном языке (CIL) есть команды упаковки и распаковки.
Некоторые компиляторы, такие как С# и Visual Basic .NET, скрывают упаковку и распаковку, пытаясь создать единое представление о системе типов. Следующий код не будет работать без упаковки, так как помещает целое в объект Hashtable, который хранит исключительно ссылки:
Hashtable table = new Hashtable (); // Создать Hashtable.
table.Add ("First", 1); // Добавить 1 с ключом "First"
Компилятор С# сгенерирует такой CIL-код:
newobj instance void
[mscorlib]Systetn.Collections.Hashtable::.ctorQ
stloc.0
ldloc.0
Idstr "First"
idc.14.1
box [mscorlib]System.Int32
callvlrt instance void
[mscorlib]System.Collections.Hashtable::Add(object, object)
Команда BOX преобразует целое число 1 в упакованный размерный тип. Компилятор вставил ее, чтобы можно было не думать о ссылочных и размерных типах.
Строка с ключевым значением («First») элемента Hashtable не подлежит упаковке, так как она является экземпляром ссылочного типа SystemString.
Многие компиляторы спокойно упаковывают значения без специальных указаний. Так. компиляция этого С#-кода проходит гладко:
int val =1 ; // Определен экземпляр размерного типа,
object obj = val; // Компилятор сам его упаковывает.
Однако распаковка ссылочного типа в Ct требует явного приведения типов:
int val = 1;
object obj = val;
int val2 = obj; // Этот оператор не пройдет компиляцию.
int val3 = (int) obj; // А этот пройдет.
Упаковка и распаковка приводят к потере производительности. Однако в подавляющем большинстве приложений выигрыш в производительности от хранения простых типов данных в стеке, а не в куче, где надо убирать мусор, значительно перевешивает эти потери.
Похожие статьи: