Это не официальный сайт wikipedia.org 01.01.2023

Упаковка и распаковка значимых типов — Википедия

Упаковка и распаковка значимых типов

Упаковка и распаковка значимых типов в C# — доступный для программиста механизм преобразования размерных типов данных языка C# из значимых в ссылочные и обратно через задействование свойств фундаментального базового класса Object.

ОписаниеПравить

Как правило, значимые типы предпочтительнее для использования, чем ссылочные: для них не нужно заботиться о динамическом выделении памяти из «кучи», на них не расходуются ресурсы при сборке мусора, по отношению к ним нет необходимости использовать адресацию через указатели. Однако, иногда необходимо использовать значимые типы совместно со ссылочными[1]. Помимо этого, для использования ряда библиотечных классов нередко возникает нужда в ссылках на экземпляры значимых типов, что заставляет применять механизм их упаковки (англ. boxing) с перспективой распаковки (англ. unboxing) в будущем[2].

УпаковкаПравить

В языке C# упаковка работает как неявное преобразование экземпляра любого размерного типа в объект базового класса Object, которое происходит, когда компилятор наталкивается на значимый тип в том контексте, где ожидается появление ссылки. Это преобразование автоматически производится библиотекой CLR причём его выполнение не зависит от того, какой именно тип передан как входной — ссылочный или значимый[3].

Трансформация значимого типа в ссылочный осуществляется автоматически, для этого выполняются следующие шаги[2]:

  1. выделение необходимых ресурсов памяти для размещения нового объекта в «куче». Объёмы этой памяти определяются длиной упаковываемого типа и размером двух служебных членов. Первый из них является указателем на объект-тип, второй — индексом SyncBlockIndex. Этими метаданными снабжаются любые объекты в области динамической памяти.
  2. поля значимого типа копируются в динамически выделенную память.
  3. возвращается адрес полученного объекта в виде ссылочного типа.

РаспаковкаПравить

Распаковка ссылочного типа в значимый подразумевает, что это должно быть выполнено явно. При этом, необходимо во-первых, сначала удостовериться, что тип упакованного объекта по ссылке соответствует исходному, а во-вторых, скопировать поля данных упакованного объекта в новую переменную данного типа. Как правило, проверку соответствия типов осуществляют с помощью механизма генерирования и обработки исключений[3], после чего копирование переносит внутренние данные (поля) объекта из «кучи» в стек выполняемого приложения, где хранятся его локальные переменные. Последовательность конкретных действий сводится к следующим шагам[2]:

  1. если служебный указатель на упакованный значимый тип имеет значение null, то генерируется исключение NullReferenceException,
  2. если упакованный объект не соответствует требуемому типу, то выбрасывается исключение InvalidCastException.

Отмечается, что распаковка не является противоположностью упаковки в строгом смысле этого слова, она гораздо менее ресурсоёмка если состоит только в запросе указателя на исходный значимый тип. Однако, в большинстве встречающихся приложений, невозможно обойтись без корректного копирования полей объекта из «кучи» в стек, что может крайне отрицательно сказаться на производительности[2].

В связи с этим отмечается, что в некоторых диалектах C++, таких как, например C++/CLI предусмотрены встроенные средства для упаковки значимого типа данных не прибегая к созданию копии его полей[2].

ПримечанияПравить

  1. Т. А. Павловская. Упаковка и распаковка // Программирование на языке высокого уровня в C#. — М.: ИНТУИТ, 2016. — С. 32.
  2. 1 2 3 4 5 Дж. Рихтер. Упаковка и распаковка значимых типов // CLR via C#. Программирование на платформе Microsoft.NET Framework 4.0 на языке С#. — 3-е. — СПб.: Питер, 2012. — С. 136. — 928 с. — ISBN 978-5-459-00297-3.
  3. 1 2 Либерти Д. Упаковка и распаковка типов // Программирование на C#. — СПб.. — 2003: Символ-Плюс, 2003. — С. 139. — 688 с. — ISBN 5-93286-038-3.

СсылкиПравить