heap.tech
лаборатория велосипедов
×

Выживание на собеседование, часть 2. Упаковка и распаковка (boxing, unboxing)

03 ноября 2016
Это вторая статья из цикла выживания на собеседованиях для IT-специалистов. На подавляющем большинстве собеседований, на которых мне посчастливилось побывать, мне задавали вопросы о том, знаю ли я что такое boxing и unboxing. Иногда беседа плавно перетекала в допрос с пристрастием о циклах. Еще реже вопросы о циклах перетекали в плоскость индексаторов и создания собственных коллекций. И наконец, самые стойкие рекрутеры, спрашивали про синтаксический сахар. В этой статье я опишу максимально подробно процесс боксинга и анбоксинга, немного затрону циклы. Про то, как устроены индексаторы, энумераторы, создание собственных коллекций я обязательно расскажу в будущих статьях, вопросы подобного типа совсем не редкость.

Ссылки на предыдущие уроки выживания
Выживание на собеседование, часть 1. Принципы SOLID

Типы данных в c#

Немного теории - в c# есть два фундаментальных типа данных (речь идет не о примитивах int, long, bool, string, а о способе хранения и доступа в памяти): ссылочные (reference type) и значимые (value type). К ссылочным относятся классы (class), к значимым структуры (struct). Ссылочные типы хранятся в управляемой куче (managed heap), а структуры в стеке (stack).

Важно
Стоит помнить, что в стеке хранятся адреса reference-type объектов. Фактически это указатель (pointer) на адрес памяти в куче, где расположен reference-type объект.

Скучный пример
static void Main() { Foo foo = null; foo = new Foo(); foo.X = (int)Math.Pow(2, 7); //128 = 0x80 foo.Y = (long)Math.Pow(2, 46); //70368744177664 = 0x4000 0000 0000 foo.bar.X = (int)Math.Pow(2, 6); //64 = 0x40 Bar bar; bar.X = 2147483647; //2147483647 = 0x7FFFFFFF } class Foo { public int X; public long Y; public Bar bar; } struct Bar { public int X; }


А вот, как это располагается в памяти



Что такое boxing (боксинг)

Boxing или упаковка — это процесс, при котором значимый экземпляр из стека (то есть структура) попадает в управляемую кучу или, проще говоря, структура становится классом. Для этого производится полное копирование всего содержимого (поля, методы, свойства, значения) объекта с значимым типом в новый объект ссылочного типа. Эти два объекта никак не связаны между собой - если изменить структуру, то созданный объект останется неизменным. И наоборот.

Процесс переноса содержимого структуры в новый объект занимает достаточно продолжительное время, поэтому его лучше избегать.

Так как же происходит упаковка ?

Упаковка или боксинг (boxing) происходит скрытно и без лишних вопросов. Программист, скорее всего, не заметит этого. Поэтому, если вам кажется, что в вашем проекте вы ничего не упаковываете, то, скорее всего вы не правы.

Простенький пример

int messageId = 146; String.Format("Message with Id {0} was sent", messageId);


messageId – это переменная с целочисленным значением, то есть int. В свою очередь int — это структура, а структура это тип, доступный по значению. Если посмотреть на метод String.Format, он принимает string, params object[]. Вот оно! Переменная messageId будет упакована в object.


Распаковка, unboxing
Если прикинуться капитаном — то можно дать очевидный ответ: распаковка это обратный процесс упаковки. Другими словами, в результате распаковки объект ссылочного типа преобразуется в значимый экземпляр, который будет помещен в стек. Созданный значимый экземпляр никаким образом не будет связан с ссылочным объектом. Процесс распаковки тоже достаточно длительный процесс, копируется все содержимое ссылочного объекта.

Explicit и implicit
Когда вы бодро и уверенно рассказали о упаковке и распаковке, скорее всего, вас спросят о том, что такое implicit и explicit. Это просто: explicit – явное преобразование, а implicit, наоборот, неявное. Как это выглядит в коде:

int i = 146; //implicit object o = i;


int i = 146; //explicit object o = (object)i;


Отличия упаковки (распаковки) и преобразования типов
Как мы уже поняли, упаковка и распаковка, по определению - это процесс, связанный только с значимыми типами (value-type или структуры). Если вы хотите выполнить преобразование экземпляра ссылочного типа Foo в обобщенный тип object – то это называется преобразование типов.

class Foo { int bar; string reason; public Foo() { this.bar = 146; this.reason = “due to math. 146 percent” } } static void Main() { Foo foo = new Foo(); //явное преобразование переменной с типом Foo к System.Object object foo_obj = (object)foo; //неявное преобразование object foo_obj2 = foo; }


Заключение
Раньше, в первых версиях .Net (.Net framework 1.x, CLR 1.x), не существовало понятия универсальных типов (Generic<T>). Поэтому боксинг был единственным способом создания универсальных коллекций.

Следующий урок выживания
Массивы, коллекции, перечисления, foreach
 
7168
0

Оставлять комментарии могут только зарегистрированные пользователи

пока никто не оставлял комментариев

Последние статьи

Сборка на водяном охлаждении. Часть 1

Компьютер на водяном охлаждении

Основы моддинга

Моддинг. Домашние компьютеры больше не унылые