Упаковка (boxing) и распаковка (unboxing) — операции преобразования значимых типов данных в ссылочные и обратно. Эти операции могут негативно сказываться на производительности из-за дополнительных вычислений: выделения памяти под новый объект и копирования данных.
Упаковка происходит при преобразовании значимого типа в тип System.Object, System.Enum, System.ValueType или интерфейса. Эта операция может быть выполнена явно и неявно:
int a = 10;
object b = a; // Неявная упаковка
object c = (object)a; // Явная упаковка
Неявная упаковка происходит, когда переменная значимого типа используется в контексте, где ожидается ссылочный тип. Примеры таких операций:
Несколько примеров рассмотрены подробнее ниже.
Пример 1
struct Point : IComparable<Point>
{
....
public int CompareTo(Point point) { .... }
}
static void
ProcessComparableItems<T>(IComparable<T> lhs,
IComparable<T> rhs)
{ .... }
static int Calculate(....)
{
var firstPoint = new Point(....);
var secondPoint = new Point(....);
ProcessComparableItems(firstPoint, secondPoint);
....
}
Метод ProcessComparableItems работает с двумя параметрами типа IComparable<T>. В то же время структура Point реализует этот интерфейс. Несмотря на это, при вызове метода ProcessComparableItems с аргументами типа Point каждый из них будет упакован:
// ProcessComparableItems(firstPoint, secondPoint);
IL_0039: ldloc.0
IL_003a: box BoxingTest.Program/Point // <=
IL_003f: ldloc.1
IL_0040: box BoxingTest.Program/Point // <=
IL_0045: call void
BoxingTest.Program::ProcessComparableItems
<valuetype BoxingTest.Program/Point>(....)
....
Пример 2
var dateTime = new DateTime(....);
Type typeInfo = dateTime.GetType();
dateTime — переменная значимого типа (DateType). У dateTime вызывается метод GetType, определённый в типе System.Object. Чтобы выполнить такой вызов, объект dateTime придётся упаковать:
// Type typeInfo = dateTime.GetType();
IL_0014: ldloc.0
IL_0015: box [System.Runtime]System.DateTime // <=
IL_001a: call instance class
[System.Runtime]System.Type
[System.Runtime]System.Object::GetType()
....
Распаковкой называют преобразование упакованного значения обратно в значимый тип. Операция распаковки имеет свои особенности:
Пример
double a = 1;
object b = a;
int c = (int)b;
Из-за несоответствия типов при попытке распаковки переменной возникнет исключение InvalidCastException. Исправленный вариант:
int c = (int)(double)b;
0