Что такое boxing / unboxing?csharp-32

Что такое Boxing?

Boxing — это процесс преобразования value type (типа значения) в reference type (ссылочный тип), а именно в object или в любой интерфейс, который реализует этот value type.

int number = 42;          // value type в стеке
object boxed = number;    // boxing: число копируется в кучу

Что происходит при Boxing:

  1. В управляемой куче выделяется память
  2. Значение value type копируется в эту область памяти
  3. Возвращается ссылка на этот объект в куче

Что такое Unboxing?

Unboxing — это обратный процесс извлечения value type из упакованного объекта.

object boxed = 42;       // Упакованное число
int unboxed = (int)boxed; // Unboxing

Особенности Unboxing:

  1. Требуется явное приведение типов
  2. Должен быть точное совпадение типов
  3. Если типы не совпадают — InvalidCastException
object boxed = 42;
long unboxed = (long)boxed; // Ошибка времени выполнения!

Примеры и нюансы

1. Boxing при передаче value type в параметр object

void Print(object obj) { /* ... */ }

int number = 10;
Print(number); // Происходит boxing

2. Boxing при приведении к интерфейсу

IFormattable formattable = 42; // Boxing происходит здесь

3. Повторный boxing

int i = 10;
object o1 = i; // Boxing 1
object o2 = i; // Boxing 2 - создается ДРУГОЙ объект

Производительность

Boxing/unboxing имеют накладные расходы:

  1. Выделение памяти в управляемой куче
  2. Копирование данных
  3. Давление на GC (дополнительные объекты для сборки)

Пример с коллекциями:

ArrayList list = new ArrayList(); // Не generic-коллекция
for (int i = 0; i < 100000; i++) {
    list.Add(i); // Boxing на каждой итерации!
}

Как избежать boxing/unboxing?

  1. Использовать generic-коллекции:

    List<int> list = new List<int>(); // Нет boxing'а
    
  2. Использовать обобщенные методы:

    void Print<T>(T value) where T : struct { /* ... */ }
    Print(42); // Нет boxing'а
    
  3. Использовать специальные интерфейсы: Для числовых типов можно использовать INumber<T>

Особые случаи

1. Boxing nullable типов

int? nullableInt = 42;
object boxed = nullableInt; // Boxing nullable типа

2. Unboxing в nullable

object boxed = 42;
int? unboxed = (int?)boxed; // Корректно

3. Работа с enum

enum Color { Red, Green }
object boxed = Color.Red; // Boxing enum

Резюмируем:


Boxing и unboxing — это механизмы преобразования между value types и reference types, которые влияют на производительность. Boxing копирует значение в кучу, создавая объект, а unboxing извлекает значение обратно. Важно минимизировать эти операции, используя generics и понимая их скрытые проявления в коде.