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

10.1.4.2Реализация интерфейсов

Спецификация базы_класса может включать список типов интерфейса, при этом считается, что класс непосредственно реализует заданные типы интерфейса. Реализация интерфейсов рассматривается более подробно в §13.4.

10.1.5Ограничения параметров типа

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

предложения_ограничений_параметров_типа: предложение_ограничений_параметров_типа предложения_ограничений_параметров_типа предложение_ограничений_параметров_типа

предложение_ограничений_параметров_типа: where параметр_типа : ограничения_параметров_типа

ограничения_параметров_типа: первичное_ограничение вторичные_ограничения ограничение_для_конструктора первичное_ограничение , вторичные_ограничения первичное_ограничение , ограничение_для_конструктора вторичные_ограничения , ограничение_для_конструктора первичное_ограничение , вторичные_ограничения , ограничение_для_конструктора

первичное_ограничение: тип_класса class struct

вторичные_ограничения: тип_интерфейса параметр_типа вторичные_ограничения , тип_интерфейса вторичные_ограничения , параметр_типа

ограничение_для_конструктора: new ( )

Каждое предложение_ограничений_параметров_типа состоит из маркера where, следующих затем имени параметра типа, двоеточия и списка ограничений для данного параметра типа. Может существовать не более одного предложения where для каждого параметра типа, порядок перечисления предложений where не имеет существенного значения. Аналогично маркерам get и set в функции доступа к свойству, маркер where не является ключевым словом.

Список ограничений в предложении where может включать любые из представленных ниже компонентов в следующем порядке: одно первичное ограничение, одно или несколько вторичных ограничений и ограничение конструктора , new().

Первичное ограничение может быть типом класса или ограничением ссылочного типа class или ограничением типа значения struct. Вторичное ограничение может быть параметром_типа или типом_интерфейса.

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

Ограничение типа значения указывает, что аргумент типа, используемый для параметра типа, не должен быть типом, который может иметь значение null. Все типы структур, которые не могут иметь значение null, типы перечислений и параметры типа с ограничением типа значения удовлетворяют данному ограничению. Обратите внимание, что, несмотря на классификацию в качестве типа значения, тип, который может иметь значение null (§4.1.10), не удовлетворяет ограничению типа значения. Параметр типа с ограничением типа значения также не может иметь ограничение_конструктора.

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

Если ограничение является типом класса, типом интерфейса или параметром типа, данный тип указывает минимальный «базовый тип», который должен поддерживать каждый аргумент типа для данного параметра типа. При использовании сформированного типа или универсального метода аргумент типа проверяется на соответствие ограничениям параметра типа во время компиляции. Предоставленный аргумент типа должен удовлетворять условиям, определенным в разделе 4.4.4.

Ограничение типа_класса должно удовлетворять следующим правилам.

  • Типом должен быть тип класса.

  • Тип не должен быть sealed.

  • Тип не должен быть одним из следующих типов: System.Array, System.Delegate, System.Enum или System.ValueType.

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

  • Максимум одно ограничение для данного параметра типа может являться типом класса.

Тип, заданный в качестве ограничения тип_интерфейса, должен удовлетворять следующим правилам:

  • Он должен быть типом интерфейса.

  • Тип не должен быть указан более одного раза в данном предложении where.

В любом случае ограничение может включать любые параметры типа связанных объявлений типа или метода в качестве части сформированного типа, а также может включать объявляемый тип.

Любой тип класса или интерфейса, указанный в качестве ограничения параметра типа, должен быть не менее доступен (§3.5.4), чем объявляемый универсальный тип или метод.

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

  • Он должен быть параметром типа.

  • Тип не должен быть указан более одного раза в данном предложении where.

Кроме того, не допускается наличие циклов в диаграмме зависимости параметров типа, где зависимостью является транзитивное отношение, заданное следующим.

  • Если параметр типа T используется в качестве ограничения для параметра типа S, то S зависит от T.

  • Если параметр типа S зависит от параметра типа T, и T зависит от параметра типа U, то S зависит от U.

Согласно данному отношению, если параметр типа зависит от самого себя (прямым или косвенным образом), это является ошибкой времени компилирования.

Любые ограничения должны быть согласованы среди зависимых параметров типа. Если параметр типа S зависит от параметра типа T, выполняется следующее.

  • T не должен иметь ограничение типа значения. В противном случае T эффективно запечатывается таким образом, что S будет принудительно того же типа, что и T, устраняя тем самым потребность в двух параметрах типа.

  • Если S имеет ограничение типа значения, то T не должен иметь ограничения типа_класса.

  • Если S имеет ограничение типа_класса A и T имеет ограничение типа_класса B, то требуется преобразование идентификации или неявные преобразования ссылочных типов из A в B (или из B в A).

  • Если S также зависит от параметра типа U, U имеет ограничение типа_класса A и T имеет ограничение типа_класса B, то требуется преобразование идентификации или неявные преобразования ссылочных типов из A в B (или из B в A).

S может иметь ограничение типа значения, и T может иметь ограничение ссылочного типа. Фактически это позволяет ограничить T до типов System.Object, System.ValueType, System.Enum и любого типа интерфейса.

Если предложение where для параметра типа включает ограничение конструктора (с формой new()), можно использовать оператор new для создания экземпляров типа (§7.6.10.1). Любой аргумент типа, используемый для параметра типа с ограничением конструктора, должен иметь открытый конструктор без параметров (данный конструктор неявно существует для любого типа значения) или должен быть параметром типа с ограничением типа значения или ограничением конструктора (подробные сведения см. в разделе §10.1.5).

Ниже представлены примеры ограничений.

interface IPrintable { void Print(); }

interface IComparable<T> { int CompareTo(T value); }

interface IKeyProvider<T> {

T GetKey(); }

class Printer<T> where T: IPrintable {...}

class SortedList<T> where T: IComparable<T> {...}

class Dictionary<K,V> where K: IComparable<K> where V: IPrintable, IKeyProvider<K>, new() { ... }

Следующий пример содержит ошибку, так как он вызывает цикличность в графе зависимостей параметров типа.

class Circular<S,T> where S: T where T: S // Error, circularity in dependency graph { ... }

Следующие примеры иллюстрируют некоторые недопустимые ситуации.

class Sealed<S,T> where S: T where T: struct // Error, T is sealed { ... }

class A {...}

class B {...}

class Incompat<S,T> where S: A, T where T: B // Error, incompatible class-type constraints { ... }

class StructWithClass<S,T,U> where S: struct, T where T: U where U: A // Error, A incompatible with struct { ... }

Эффективный базовый класс параметра типа T определяется следующим образом.

  • Если T не имеет первичных ограничений или ограничений параметра типа, его эффективным базовым классом является object.

  • Если T имеет ограничение типа значения, его эффективным базовым классом является System.ValueType.

  • Если T имеет ограничение типа_класса C, но не имеет ограничений параметра_типа, его эффективным базовым классом является C.

  • Если T не имеет ограничения типа_класса, но имеет одно или более ограничений параметра_типа, его эффективным базовым классом является наивысший заключенный тип (§6.4.2) в наборе эффективных базовых классов его ограничений параметра_типа. Правила соответствия обеспечивают существование наивысшего заключенного типа.

  • Если T имеет ограничение типа_класса и одно или более ограничений параметра_типа, его эффективным базовым классом является наивысший заключенный тип (§6.4.2) в наборе, состоящем из ограничения типа_класса T и эффективных базовых классов его ограничений параметра_типа. Правила соответствия обеспечивают существование наивысшего заключенного типа.

  • Если T имеет ограничение ссылочного типа, но не имеет ограничений типа_класса, его эффективным базовым классом является object.

Для выполнения этих правил, если T имеет ограничение V, имеющее тип_значения, используйте более конкретный базовый тип V типа_класса. Это не может произойти в явно предоставленном ограничении, но может случиться, когда ограничения универсального метода неявным образом наследуются объявлением метода переопределения или явной реализацией метода интерфейса.

Эти правила обеспечивают то, что эффективным базовым классом всегда является тип_класса.

Эффективный набор интерфейса параметра типа T определяется следующим образом.

  • Если T не имеет вторичных_ограничений, его эффективный набор интерфейсов пуст.

  • Если T имеет ограничения типа_интерфейса, но не имеет ограничений параметр_ типа, его эффективным набором интерфейса является его набор ограничений типа_интерфейса.

  • Если T не имеет ограничений типа_интерфейса, но имеет ограничения параметра_типа, его эффективным набор интерфейса является объединение эффективных наборов интерфейса его ограничений параметра_типа.

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

Параметр типа считается ссылочным типом, если он имеет ограничение ссылочного типа, или если его эффективным базовым классом не является object или System.ValueType.

Значения ограниченного типа для типа параметра могут использоваться для доступа к членам экземпляров, подразумеваемых ограничениями. Рассмотрим пример:

interface IPrintable { void Print(); }

class Printer<T> where T: IPrintable { void PrintOne(T x) { x.Print(); } }

В этом примере методы IPrintable могут быть вызваны непосредственно для x, так как T ограничен постоянно реализовывать IPrintable.

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