Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Операции и приведения.docx
Скачиваний:
3
Добавлен:
01.07.2025
Размер:
200 Кб
Скачать
☆

Упаковка и распаковка

В разделе 6.2 вы узнали, что все типы  простые предопределенные вроде int и char, а также сложные наподобие классов и структур  наследуются от типа object. Это значит, что даже с литералами можно обращаться как с объектами:

string s = 10.ToString();

Однако вы также видели, что типы данных C# подразделяются на типы значений, кото­рые размещаются в стеке, и ссылочные типы, размещаемые в куче. Как объяснить возмож­ность вызова методов для int, если int  не более чем четырехбайтовое значение в стеке?

Способ, который использует C# для достижения такого эффекта, называется упаковкой (boxing); Упаковка и ее противоположность  распаковка (unboxing)  позволяют преоб­разовывать типы значений в ссылочные типы и затем обратно в типы значений. Эта тема была включена в раздел, посвященный приведению, потому, что, по сути, при этом выпол­няется приведение значения к типу object. Упаковка  термин, применяемый для описа­ния трансформации типа значения в ссылочный тип. В основном, при этом исполняющая среда создает временный “ящик” типа ссылки на объект в куче.

Такое преобразование может происходить неявно, как в предыдущем примере, но его можно также выполнять явно:

int myIntNumber = 20;

object myObject = myIntNumber;

Распаковка  это термин, описывающий обратный процесс, когда ранее упакованная величина приводится обратно к типу значений. Здесь используется термин приведение, по­скольку это должно быть сделано явно. Используемый синтаксис подобен тому, что приме­няется при явном приведении типов, описанном выше:

int myIntNumber = 20;

object myObject = mylntNumber; // Упаковать int

int mySecondNumber = (int)myObject; // Распаковать обратно в int

Вы можете распаковать только ту переменную, которая была ранее упакована. Если выполнить последнюю строку, когда myObject не является упаковкой для int, во время выполнения будет сгенерировано исключение.

Одно важное предостережение: при распаковке следует соблюдать осторожность, что­бы принимающая переменная имела в себе достаточно места для сохранения всех байтов распаковываемого значения. Например, int в C# имеет длину только 32 бита, а потому распаковка значения long (длиной 64 бита) в int, как показано ниже, приведет к генера­ции исключения InvalidCastException:

long myLongNumber = 333333423;

object myObject = (object)myLongNumber;

int mylntNumber = (int)myObject;

Проверка равенства объектов

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

Механизмы сравнения объектов различаются в зависимости от того, сравниваются ли ссылочные типы (экземпляры классов) или же типы значений (примитивные типы дан­ных, экземпляры структур или перечислений). В последующих разделах мы независимо рассмотрим сравнение ссылочных типов и типов значений.

Сравнение ссылочных типов на эквивалентность

Один аспект System.Object, который на первый взгляд может показаться неожидан­ным  это тот факт, что в нем определены три разных метода ддя проверки эквивалентно­сти объектов: ReferenceEquals() и две версии Equals(). Добавьте сюда операцию срав­нения (==) и вы получите четыре способа проверки равенства. Между этими способами существуют тонкие отличия, которые описаны ниже.

Метод ReferenceEquals()

ReferenceEquals()  статический метод, проверяющий, указывают ли две ссылки на один и тот же экземпляр класса; точнее  содержат ли две ссылки один и тот адрес памяти. Поскольку это статический метод, который невозможно переопределить, его реализация из System.Object  это то, что доступно всегда. ReferenceEquals() всегда будет возвра­щать true, когда ему передаются две ссылки, указывающие на один и тот же экземпляр объ­екта, и false  в противном случае. Однако две ссылки на null трактуются как равные:

SomeClass х, у;

х = new SomeClass() ;

у = new SomeClass();

bool В1 = ReferenceEquals(null,null); //возвращает true

bool B2 = ReferenceEquals(null,x); //возвращает false

bool B3 = ReferenceEquals (x, у) ; //возвращает false, потому что

//x и у указывают на разные объекты