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

6.2.5Преобразования распаковки

Преобразование распаковки обеспечивает явное преобразование ссылочного_типа к типу_значений. An unboxing conversion exists from the types object, dynamic and System.ValueType to any non-nullable-value-type, and from any interface-type to any non-nullable-value-type that implements the interface-type. Кроме того, может быть выполнена распаковка System.Enum в любой перечисляемый_тип.

Преобразование распаковки из ссылочного типа к обнуляемому_типу существует в том случае, если существует преобразование распаковки из ссылочного типа к необнуляемому_типу_значений, являющемуся базовым для обнуляемого_типа.

Тип значений S имеет преобразование распаковки из интерфейса типа I, при наличии преобразования распаковки типа интерфейса I0 и при наличии у I0 преобразования идентификатора к I.

Тип значений S имеет преобразование распаковки из интерфейса типа I, при наличии преобразования распаковки типа интерфейса или делегата I0 и наличии у I0 вариантов преобразований к I или наличии у I вариантов преобразований (§13.1.3.2) к I0.

При выполнении операции распаковки сначала проверяется, является ли экземпляр объекта упакованным значением указанного типа_значений. После этого выполняется копирование значения из экземпляра. При распаковке пустой ссылки в обнуляемый_тип возвращается значение null обнуляемого_типа. Структура может быть распакована в тип System.ValueType, поскольку он является базовым классом для всех структур (§11.3.2).

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

6.2.6Неявные динамические преобразования

Существует явное динамическое преобразование из выражения типа dynamic к типу T. При этом выполняется динамическая привязка преобразования (§7.2.2), что означает, что потребуется явное преобразование во время выполнения из типа времени выполнения выражения к T. Если преобразование не обнаружено, во время выполнения возникает исключение.

Если динамическая привязка преобразования не требуется, выражение можно сначала преобразовать к object, а затем к необходимому типу.

Предположим, что существуют следующие классы.

class C { int i;

public C(int i) { this.i = i; }

public static explicit operator C(string s) { return new C(int.Parse(s)); } }

Следующий пример иллюстрирует явное динамическое преобразование:

object o = "1"; dynamic d = "2";

var c1 = (C)o; // Compiles, but explicit reference conversion fails var c2 = (C)d; // Compiles and user defined conversion succeeds

Лучший способ преобразования o к C времени компиляции это явное преобразование ссылки. Во время выполнения происходит ошибка, поскольку "1" не является C. Преобразование d к C в качестве явного динамического преобразования откладывается на время выполнения, когда обнаруживается и успешно выполняется преобразование, определяемое пользователем, из типа времени выполнения d – string – к C.

6.2.7Явные преобразования, включающие параметры типа

Существуют следующие явные преобразования для заданного параметра типа T:

  • Из эффективного базового для типа T класса C к T, а также из любого базового для C класса к T. At run-time, if T is a value type, the conversion is executed as an unboxing conversion. В противном случае преобразование выполняется как явное преобразование ссылочного типа или идентификатора.

  • Из любого типа интерфейса к T. Если T является типом значений, во время выполнения преобразование выполняется как преобразование распаковки. В противном случае преобразование выполняется как явное преобразование ссылочного типа или идентификатора.

  • Из T к любому типу_интерфейса I, если уже не существует неявного преобразования из T к I. Если T является типом значений, во время выполнения преобразование выполняется как преобразование упаковки с последующим явным преобразованием ссылочного типа. В противном случае преобразование выполняется как явное преобразование ссылочного типа или идентификатора.

  • Из параметра типа U к T, если T зависит от U (§10.1.5). Если в процессе выполнения U имеет тип значений, то T и U обязательно имеют один тип и преобразование не выполняется. Если в процессе выполнения T является типом значений, во время выполнения преобразование выполняется как преобразование распаковки. В противном случае преобразование выполняется как явное преобразование ссылочного типа или идентификатора.

Если T является ссылочным типом, все описанные выше преобразования классифицируются как явные преобразования ссылочных типов (§6.2.4). Если T не является ссылочным типом, описанные выше преобразования классифицируются как преобразования распаковки (§6.2.5).

Приведенные выше правила не допускают прямого явного преобразования из безусловного параметра типа к типу, не являющемуся интерфейсом, поскольку его результат может быть непредсказуем. Это связано с необходимостью избежать несогласованности и достичь более точного представления семантики таких преобразований. Например, рассмотрим следующее заявление:

class X<T> { public static long F(T t) { return (long)t; // Error } }

Если разрешено прямое явное преобразование из t к int, можно предполагать, что выражение X<int>.F(7) возвратит 7L. Однако результат будет другим, поскольку стандартные преобразования числовых типов применяются только в том случае, если типы являются числовыми во время привязки. Чтобы семантика была понятной, этот пример необходимо записать следующим образом:

class X<T> { public static long F(T t) { return (long)(object)t; // Ok, but will only work when T is long } }

Код будет скомпилирован, однако при выполнении выражения X<int>.F(7) будет порождено исключение времени выполнения, поскольку упакованное значение int не может быть напрямую преобразовано в long.

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