Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
CSharp Language Specification.doc
Скачиваний:
13
Добавлен:
26.09.2019
Размер:
4.75 Mб
Скачать

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

Значение с типом класса можно преобразовать в тип object или в тип интерфейса, реализуемого этим классом, путем обработки данной ссылки во время компиляции как другого типа. Аналогичным образом значение с типом object или типом интерфейса можно преобразовать обратно в тип класса без изменения ссылки (естественно, в этом случае требуется проверка во время выполнения).

Так как структуры не относятся к ссылочным типам, для типов структуры эти операции реализуются по-другому. При преобразовании значения с типом структуры в тип object или в тип интерфейса, реализуемый этой структурой, происходит операция упаковки. Точно так же при обратном преобразовании значения с типом object или значения с типом интерфейса в тип структуры выполняется операция распаковки. Ключевое отличие от аналогичных операций с типами класса состоит в том, что при упаковке и распаковке выполняется копирование значения структуры в упакованный экземпляр или из такого экземпляра. Таким образом, после выполнения операции упаковки или распаковки изменения, внесенные в распакованную структуру, не отражаются в упакованной структуре.

Если в структуре переопределяется виртуальный метод, унаследованный из класса System.Object (например, Equals, GetHashCode или ToString), вызов этого виртуального метода в экземпляре типа структуры не ведет к выполнению упаковки. Это правило действует даже в том случае, когда структура используется в качестве параметра типа и вызов происходит в экземпляре с типом параметра типа. Пример:

using System;

struct Counter { int value;

public override string ToString() { value++; return value.ToString(); } }

class Program { static void Test<T>() where T: new() { T x = new T(); Console.WriteLine(x.ToString()); Console.WriteLine(x.ToString()); Console.WriteLine(x.ToString()); }

static void Main() { Test<Counter>(); } }

Результат выполнения примера:

1 2 3

Несмотря на то, что использование метода ToString для выполнения побочных действий является плохим стилем, в этом примере демонстрируется, что при трех вызовах метода x.ToString() упаковка не выполнялась.

Аналогичным образом упаковка не выполняется неявным образом при доступе к члену с ограниченным параметром-типом. Например, интерфейс ICounter содержит метод Increment, который можно использовать для изменения значения. Если метод ICounter используется в качестве ограничения, реализация метода Increment вызывается со ссылкой на переменную, для которой был вызван метод Increment, а не для упакованной копии.

using System;

interface ICounter { void Increment(); }

struct Counter: ICounter { int value;

public override string ToString() { return value.ToString(); }

void ICounter.Increment() { value++; } }

class Program { static void Test<T>() where T: ICounter, new() { T x = new T(); Console.WriteLine(x); x.Increment(); // Modify x Console.WriteLine(x); ((ICounter)x).Increment(); // Modify boxed copy of x Console.WriteLine(x); }

static void Main() { Test<Counter>(); } }

При первом вызове метода Increment изменяется значение переменной x. Это не равноценно второму вызову метода Increment, при котором изменяется значение упакованной копии x. Таким образом, в результате выполнения программы будет получен следующий результат:

0 1 1

Дополнительные сведения об упаковке и распаковке см. в §4.3.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]