В чём разница между ref/out параметрами и Boxing/Unboxing в C#?

«В чём разница между ref/out параметрами и Boxing/Unboxing в C#?» — вопрос из категории C# Core, который задают на 25% собеседований C# Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Это две совершенно разные концепции, работающие на разных уровнях.

ref и out (передача по ссылке)

Это модификаторы параметров методов, которые заставляют передавать ссылку на переменную, а не её значение.

  • Цель: Позволить методу изменять переменную, переданную вызывающим кодом.
  • ref (ссылка с инициализацией):
    • Переменная должна быть инициализирована перед передачей в метод.
    • Метод может, но не обязан изменять её значение.
      void Increment(ref int number) { number++; }
      int x = 5;
      Increment(ref x); // x теперь равен 6
  • out (ссылка для вывода):
    • Переменная НЕ требует инициализации перед передачей.
    • Метод ОБЯЗАН присвоить ей значение перед возвратом.
    • Часто используется для методов, возвращающих несколько значений.
      bool TryParse(string input, out int result)
      {
      return int.TryParse(input, out result); // result присваивается внутри TryParse
      }
      if (TryParse("123", out int number)) { /* number = 123 */ }

Boxing и Unboxing (преобразование типов значений)

Это процессы преобразования между типом значения (value type, например, int, struct) и ссылочным типом object (или любым другим интерфейсом, который реализует структура).

  • Цель: Позволить типам значений участвовать в операциях, требующих ссылочного типа (например, добавление в необобщённую коллекцию ArrayList).
  • Boxing (упаковка): Копирование значения типа из стека в управляемую кучу и создание ссылки (object) на это значение.
    int value = 42;
    object boxed = value; // Boxing: аллокация в куче, копирование значения 42.
  • Unboxing (распаковка): Извлечение значения из упакованного объекта обратно в тип значения. Требует явного приведения типа.
    int unboxed = (int)boxed; // Unboxing: копирование значения из кучи обратно в стек.
  • Ключевая проблема: Производительность. Boxing/Unboxing создаёт нагрузку из-за выделения памяти в куче и сборки мусора. Всегда предпочитайте обобщённые коллекции (List<int>) необобщённым (ArrayList).

Итог: ref/out — это про способ передачи аргументов в метод. Boxing/Unboxing — это про неявное преобразование типов, которое влияет на производительность и семантику хранения данных.