Как же эти различные категории типов обеспечивают более эффективную работу системы? Это делается с помощью
упаковки
(boxing). В простейшем случае при упаковке размерный тип преобразуется в ссылочный. В обратном случае ссылочный тип
распаковывается
(unbox) в размерный.
Замечательно в данной методике то, что объект лишь тогда является объектом, когда это необходимо. Допустим, вы объявляете переменную типа
System.Int32.
Для нее выделяется память в стеке. Вы можете передавать эту переменную любому методу, определенному в качестве принимающего аргументы типа
System.Object,
а также обращаться к любому из ее членов, к которому у вас есть доступ. Поэтому вы воспринимаете и ощущаете ее как объект. Но в реальности это всего 4 байта в стеке.
Только когда вы пытаетесь использовать эту переменную согласно правилам, определенным интерфейсом базового класса
System.Object,
система автоматически упаковывает переменную, в результате чего она становится ссылочным типом и может быть использована так же, как любой объект. Упаковка — это механизм, посредством которого в С# любая сущность может быть представлена в виде объекта. Это позволяет избежать издержек, неизбежных в том случае, если б всякая сущность на самом деле была объектом. Обратимся к примерам:
int foo = 42; // Размерный тип.
object bar = foo; // Переменная foo упакована в bar.
В первой строке этого кода мы создавали переменную
(foo)
типа
int.
Как вам известно,
int
является размерным типом (поскольку это базисный тип). Во второй строке компилятор обнаружит, что переменная
foo
скопирована в ссылочный тип, представленный переменной
bar.
При этом компилятор добавит код MSIL, необходимый для упаковки этой переменной.
А теперь выполним явное приведение типов, чтобы преобразовать
bar
обратно в размерный тип:
int foo = 42; // Размерный тип.
object bar = foo; // Переменная foo упакована в bar.
int foo2 = (int)bar; // Распаковка и приведение к типу int.
При упаковке (т. е. преобразовании из размерного типа в ссылочный) явного приведения типов не требуется. Однако при распаковке — преобразовании из ссылочного типа в размерный — приведение типов необходимо. Это так, потому что в случае распаковки объект может быть приведен к любому типу. Преобразование позволяет компилятору проверить, возможно ли приведение для заданного типа переменной. Поскольку приведение типов подчинено строгим правилам, определяемым CTS, мы рассмотрим этот случай подробнее в разделе «Приведение типов».