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

13.4.2Уникальность реализованных интерфейсов

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

interface I<T> { void F(); }

class X<U,V>: I<U>, I<V> // Error: I<U> and I<V> conflict { void I<U>.F() {...} void I<V>.F() {...} }

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

I<int> x = new X<int,int>(); x.F();

Чтобы определить, является ли список объявлений универсального типа допустимым, требуется выполнить следующие шаги:

  • L — список интерфейсов, непосредственно определенных в универсальном объявлении класса, структуры или интерфейса C.

  • Добавить в L все базовые интерфейсы для интерфейсов, уже содержащихся в L.

  • Удалить из L все дубликаты

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

В приведенном выше объявлении класса X список интерфейсов L состоит из интерфейсов I<U> и I<V>. Объявление является недопустимым, поскольку в любом сформированном типе, где U и V имеют одинаковый тип, эти два интерфейса также будут иметь одинаковый тип.

Можно объединять интерфейсы, находящиеся на разных уровнях наследования:

interface I<T> { void F(); }

class Base<U>: I<U> { void I<U>.F() {…} }

class Derived<U,V>: Base<U>, I<V> // Ok { void I<V>.F() {…} }

Этот код является допустимым, несмотря на то, что в классе Derived<U,V> реализуются как интерфейс I<U>, так и интерфейс I<V>. Код

I<int> x = new Derived<int,int>(); x.F();

вызовет метод класса Derived, поскольку класс Derived<int,int> фактически выполняет I<int> (§13.4.6).

13.4.3Реализация универсальных методов

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

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

interface I<A,B,C> { void F<T>(T t) where T: A; void G<T>(T t) where T: B; void H<T>(T t) where T: C; }

class C: I<object,C,string> { public void F<T>(T t) {...} // Ok public void G<T>(T t) where T: C {...} // Ok public void H<T>(T t) where T: string {...} // Error }

Метод C.F<T> неявно реализует метод I<object,C,string>.F<T>. В этом случае в методе C.F<T> не требуется (и не допускается) указывать ограничение T: object, так как object является неявным ограничением для всех параметров типа. Метод C.G<T> неявно реализует метод I<object,C,string>.G<T>, поскольку ограничения совпадают с установленными в интерфейсе после замены параметров типа интерфейса соответствующими аргументами типа. Ограничение для метода C.H<T> является ошибочным, так как запечатанные типы ( в данном случае string) не могут использоваться как ограничения. Отсутствие ограничения также было бы ошибкой, поскольку ограничения в неявных реализациях метода интерфейса должны совпадать. Таким образом, выполнить неявную реализацию метода I<object,C,string>.H<T> невозможно. Этот метод интерфейса может быть реализован только с использованием явной реализации члена интерфейса:

class C: I<object,C,string> { ...

public void H<U>(U u) where U: class {...}

void I<object,C,string>.H<T>(T t) { string s = t; // Ok H<T>(t); } }

В этом примере явная реализация члена интерфейса вызывает открытый метод с применением более мягких ограничений. Обратите внимание, что присваивание из t в s является допустимым, поскольку T наследует ограничение T: string, хотя это ограничение и не указано в исходном коде.

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