Упаковка и распаковка значимых типов (Boxing and Unboxing)

C#   23 Февраль 2012  Автор статьи:  

Очень часто программисты сталкиваются с ситуацией, когда им необходимо получить ссылку на объект значимого типа. Допустим нам необходимо поместить объект значимого типа в ArrayList, но мы знаем, что ArrayList это коллекция объектов ссылочного типа, то есть в качестве параметра ему необходимо передать ссылку. Но данный код вполне работоспособен:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
namespace ConsoleApplication
{
    class Program
    {
        struct Person
        {
            public string name;
            public string secondName;
        }
        static void Main(string[] args)
        {
            ArrayList company = new ArrayList();
            Person p;
            p.name = "Ivan";
            p.secondName = "Ivanov";
            company.Add(p);
   
        }
    }
}

Дело в том, что C# поддерживает специальный механизм упаковки и распаковки значимых типов. Давайте подробнее рассмотрим, что же происходит, при вызове метода Add. Компилятор выделяет место в управляемой куче под объект типа Person, копирует туда значения всех полей и возвращает ссылку на этот объект, таким образом, значимый тип превращается в ссылочный. Стоит заметить, что теперь объект который находится в коллекции и объект p никак между собой не взаимодействуют, то есть если мы изменим поле объекта p, то объект в коллекции никак не изменится. Таким образом, можно сделать вывод, что продолжительность жизни упакованного значимого типа больше чем не упакованного. В нашем случае, компилятор самостоятельно создал код для упаковки объекта, однако не все языки могут этим похвастаться, например в C++ вам самим пришлось бы писать этот код. Но не стоит забывать о том, что запаковка это очень затратный процесс, поэтому в я советую использовать Generic коллекции, которые могут хранить в себе объекты значимых типов не прибегая к их упаковки, что значительно повышает производительность. Теперь давайте перейдем к механизму распаковки объектов.

1
Person p1 = (Person)company[0];

В данном случае произошло следующее, компилятор получил ссылку на объект в управляемой куче и скопировал все его поля в созданный объект p1. Распаковка гораздо менее ресурсозатратна чем упаковка. Стоит быть осторожным при распаковки объектов, так как если ссылка будет указывать на null произойдет исключение NullReferenceException, если же упакованный тип не соответствует типу к которому его приводят при распаковки, мы получим InvalidCastException.

Научиться программировать

  • на Delphi

  • на Java

  • на C++