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 '
Помните, что в отличие от обычного приведения распаковка
InvalidCastException. Для обеспечения высокой безопасности каждая операция распаковки должна быть помещена внутрь конструкции try/catch, но такое действие со всеми операциями распаковки в приложении может оказаться достаточно трудоемкой задачей. Ниже показан измененный код, который выдаст ошибку из-за того, что в нем предпринята попытка распаковки упакованного значения int в тип long:static void SimpleBoxUnboxOperation()
{
// Создать переменную ValueType (int).
int myInt = 25;
// Упаковать int в ссылку на object.
object boxedInt = myInt;
// Распаковать в неподходящий тип данных, чтобы
// инициировать исключение времени выполнения.
try
{
long unboxedLong = (long)boxedInt;
}
catch (InvalidCastException ex)
{
Console.WriteLine(ex.Message);
}
}
На первый взгляд упаковка/распаковка может показаться довольно непримечательным средством языка, с которым связан больше академический интерес, нежели практическая ценность. В конце концов, необходимость хранения локального типа значения в локальной переменной object
System.Object, а среда CoreCLR самостоятельно позаботится о деталях, касающихся памяти.Давайте обратимся к практическому применению описанных приемов. Мы будем исследовать класс System.Collections.ArrayList
ArrayList перечислены ниже. Обратите внимание, что они прототипированы для работы с данными типа System.Object. Теперь рассмотрим методы Add(), Insert() и Remove(), а также индексатор класса:public class ArrayList : IList, ICloneable
{
...
public virtual int Add(object?
public virtual void Insert(int index, object?
public virtual void Remove(object?
public virtual object?
}
Класс ArrayList
object, которые представляют данные, находящиеся в куче, поэтому может показаться странным, что следующий код компилируется и выполняется без ошибок:static void WorkWithArrayList()
{
// Типы значений автоматически упаковываются при передаче
// методу, который требует экземпляр типа object.
ArrayList myInts = new ArrayList();
myInts.Add(10);
myInts.Add(20);
myInts.Add(35);
}
Хотя здесь числовые данные напрямую передаются методам, которые требуют экземпляров типа object
ArrayList с применением индексатора типа, находящийся в куче объект должен быть распакован в целочисленное значение, расположенное в стеке, посредством операции приведения. Не забывайте, что индексатор ArrayList возвращает элементы типа System.Object, а не System.Int32:static void WorkWithArrayList()
{
// Типы значений автоматически упаковываются,
// когда передаются члену, принимающему object.
ArrayList myInts = new ArrayList();
myInts.Add(10);
myInts.Add(20);
myInts.Add(35);
// Распаковка происходит, когда объект преобразуется
// обратно в данные, расположенные в стеке.
int i = (int)myInts[0];