Язык программирования C#9 и платформа .NET5. Страница 198
static void SimpleBoxUnboxOperation(){ // Создать переменную ValueType (int). int myInt = 25; // Упаковать int в ссылку на object. object boxedInt = myInt;}Упаковку можно формально определить как процесс явного присваивания данных типа значения переменной
System.ObjectПротивоположная операция также разрешена и называется распаковкой (unboxing). Распаковка представляет собой процесс преобразования значения, хранящегося в объектной ссылке, обратно в соответствующий тип значения в стеке. Синтаксически операция распаковки выглядит как обычная операция приведения, но ее семантика несколько отличается. Среда CoreCLR начинает с проверки того, что полученный тип данных эквивалентен упакованному типу, и если это так, то копирует значение в переменную, находящуюся в стеке. Например, следующие операции распаковки работают успешно при условии, что лежащим в основе типом
boxedIntintstatic void SimpleBoxUnboxOperation(){ // Создать переменную ValueType (int). int myInt = 25; // Упаковать int в ссылку на object. object boxedInt = myInt; // Распаковать ссылку обратно в int. int unboxedInt = (int)boxedInt;}Когда компилятор C# встречает синтаксис упаковки/распаковки, он выпускает код CIL, который содержит коды операций
box/unboxildasm.exe.method assembly hidebysig static void '<<Main>$>g__SimpleBoxUnboxOperation|0_0'() cil managed{ .maxstack 1 .locals init (int32 V_0, object V_1, int32 V_2) IL_0000: nop IL_0001: ldc.i4.s 25 IL_0003: stloc.0 IL_0004: ldloc.0 IL_0005: box [System.Runtime]System.Int32 IL_000a: stloc.1 IL_000b: ldloc.1 IL_000c: unbox.any [System.Runtime]System.Int32 IL_0011: stloc.2 IL_0012: ret } // end of method '<Program>$'::'<<Main>$>g__SimpleBoxUnboxOperation|0_0'Помните, что в отличие от обычного приведения распаковка обязана осуществляться только в подходящий тип данных. Попытка распаковать порцию данных в некорректный тип приводит к генерации исключения
InvalidCastExceptiontry/catchintlongstatic void SimpleBoxUnboxOperation(){ // Создать переменную ValueType (int). int myInt = 25; // Упаковать int в ссылку на object. object boxedInt = myInt;<b> // Распаковать в неподходящий тип данных, чтобы</b><b> // инициировать исключение времени выполнения.</b> try { long unboxedLong = (long)boxedInt; } catch (InvalidCastException ex) { Console.WriteLine(ex.Message); }}На первый взгляд упаковка/распаковка может показаться довольно непримечательным средством языка, с которым связан больше академический интерес, нежели практическая ценность. В конце концов, необходимость хранения локального типа значения в локальной переменной
objectSystem.ObjectДавайте обратимся к практическому применению описанных приемов. Мы будем исследовать класс
System.Collections.ArrayListArrayListSystem.ObjectAdd()Insert()Remove()public class ArrayList : IList, ICloneable{... public virtual int Add(<b>object?</b> value); public virtual void Insert(int index, <b>object?</b> value);