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

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

Описание

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

Упаковка

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

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

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

Распаковка

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

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

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

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

Примечания

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

Ссылки

Источник —

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