Добавить в цитаты Настройки чтения

Страница 301 из 502

<b>    return &quot;Это объект класса Alpha.&quot;;</b>

<b>  }</b>

<b>  // ...</b>

<b>}</b>

<b>class Beta : Alpha {</b>

<b>  public override string ToString() {</b>

<b>    return &quot;Это объект класса Beta.&quot;;</b>

<b>  }</b>

<b>  // ...</b>

<b>}</b>

<b>class VarianceDemo {</b>

<b>  static void Main() {</b>

<b>    // Создать ссылку из интерфейса IMyContraVarGenIF&lt;Alpha&gt;</b>

<b>    //на объект типа MyClass&lt;Alpha&gt;.</b>

<b>    // Это вполне допустимо как при наличии контравариантности, так и без нее. </b>

<b>    IMyContraVarGenIF&lt;Alpha&gt; AlphaRef = new MyClass&lt;Alpha&gt;();</b>

<b>    // Создать ссылку из интерфейса IMyContraVarGenIF&lt;beta&gt;</b>

<b>    // на объект типа MyClass&lt;Beta&gt;.</b>

<b>    //И это вполне допустимо как при наличии контравариантности,</b>

<b>    // так и без нее.</b>

<b>    IMyContraVarGenIF&lt;Beta&gt; BetaRef = new MyClass&lt;Beta&gt;();</b>

<b>    // Создать ссылку из интерфейса IMyContraVarGenIF&lt;beta&gt;</b>

<b>    //на объект типа MyClass&lt;Alpha&gt;.</b>

<b>    // *** Это вполне допустимо благодаря контравариантности. ***</b>

<b>    IMyContraVarGenIF&lt;Beta&gt; BetaRef2 = new MyClass&lt;Alpha&gt;();</b>

<b>    // Этот вызов допустим как при наличии контравариантности, так и без нее.</b>

<b>    BetaRef.Show(new Beta());</b>

<b>    // Присвоить переменную AlphaRef переменной BetaRef.</b>

<b>    // *** Это вполне допустимо благодаря контравариантности. ***</b>

<b>    BetaRef = AlphaRef;</b>

<b>    BetaRef.Show(new Beta());</b>

<b>  }</b>

<b>}</b>

Выполнение этой программы дает следующий результат.

<b>Это объект класса Beta.</b>

<b>Это объект класса Beta.</b>

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

<b>public interface IMyContraVarGenIF2&lt;in Т&gt; : IMyContraVarGenIF&lt;T&gt; {</b>

<b>  // ...</b>

<b>}</b>

Следует иметь в виду, что указывать ключевое слово in в объявлении базового интерфейса не только не нужно, но и не допустимо. Более того, сам расширенный интерфейс IMyContraVarGenIF2 не обязательно должен быть контравариантным. Иными словами, обобщенный тип Т в интерфейсе IMyContraVarGenIF2 не требуется модифицировать ключевым словом in. Разумеется, все преимущества, которые сулит контравариантность в интерфейсе IMyContraVarGen, при этом будут утрачены в интерфейсе IMyContraVarGenIF2.

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

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

Ниже приведен пример контравариантного делегата.

<b>// Объявить делегат, контравариантный по отношению к обобщенному типу Т.</b>

<b>delegate bool SomeOp&lt;in Т&gt;(Т obj);</b>

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

А вот пример ковариантного делегата.

<b>// Объявить делегат, ковариантный по отношению к обобщенному типу Т.</b>

<b>delegate Т AnotherOp&lt;out Т, V&gt;(V obj);</b>

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

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

<b>// Продемонстрировать конвариантность и контравариантность</b>

<b>// в обобщенных делегатах.</b>

<b>using System;</b>

<b>// Объявить делегат, контравариантный по отношению к обобщенному типу Т.</b>