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

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

<b>  }</b>

<b>}</b>

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

А теперь рассмотрим следующую простую реализацию иерархии классов.

<b>// Создать простую иерархию классов,</b>

<b>class Alpha {</b>

<b>  string name;</b>

<b>  public Alpha(string n) { name = n; }</b>

<b>  public string GetName() { return name; }</b>

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

<b>}</b>

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

<b>  public Beta(string n) : base (n) { }</b>

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

<b>}</b>

Как видите, класс Beta является производным от класса Alpha.

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

<b>// Создать ссылку из интерфейса IMyCoVarGenIF на объект типа MyClass&lt;Alpha&gt;.</b>

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

<b>IMyCoVarGenIF&lt;Alpha&gt; AlphaRef =</b>

<b>         new MyClass&lt;Alpha&gt;(new Alpha(&quot;Alpha #1&quot;));</b>

<b>Console.WriteLine(&quot;Имя объекта, на который ссылается переменная AlphaRef: &quot; +</b>

<b>        AlphaRef.GetObject().GetName());</b>

<b>//А теперь создать объект MyClass&lt;Beta&gt; и присвоить его переменной AlphaRef.</b>

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

<b>AlphaRef = new MyClass&lt;Beta&gt;(new Beta(&quot;Beta #1&quot;));</b>

<b>Console.WriteLine(&quot;Имя объекта, на который теперь ссылается &quot; +</b>

<b>       &quot;переменная AlphaRef: &quot; + AlphaRef.GetObject().GetName());</b>

Прежде всего, переменной AlphaRef типа IMyCoVarGenIF&lt;Alpha&gt; в этом фрагменте кода присваивается ссылка на объект типа MyClass&lt;Alpha&gt;. Это вполне допустимая операция, поскольку в классе MyClass реализуется интерфейс IMyCoVarGenIF, причем и в том, и в другом в качестве аргумента типа указывается Alpha. Далее имя объекта выводится на экран при вызове метода GetName() для объекта, возвращаемого методом GetObject(). И эта операция вполне допустима, поскольку Alpha — это и тип, возвращаемый методом GetName(), и обобщенный тип Т. После этого переменной AlphaRef присваивается ссылка на экземпляр объекта типа MyClass<Beta>, что также допустимо, потому что класс Beta является производным от класса Alpha, а обобщенный тип Т — ковариантным в интерфейсе IMyCoVarGenIF. Если бы любое из этих условий не выполнялось, данная операция оказалась бы недопустимой.

Ради большей наглядности примера вся рассмотренная выше последовательность операций собрана ниже в единую программу.

<b>// Продемонстрировать ковариантность в обобщенном интерфейсе,</b>

<b>using System;</b>

<b>// Этот обобщенный интерфейс поддерживает ковариантность.</b>

<b>public interface IMyCoVarGenIF&lt;out Т&gt; {</b>

<b>  Т GetObject();</b>

<b>}</b>

<b>// Реализовать интерфейс IMyCoVarGenIF.</b>

<b>class MyClass&lt;T&gt; : IMyCoVarGenIF&lt;T&gt; {</b>

<b>  T obj;</b>

<b>  public MyClass(T v) { obj = v; }</b>

<b>  public T GetObject() { return obj; }</b>

<b>}</b>

<b>// Создать простую иерархию классов,</b>

<b>class Alpha {</b>

<b>  string name;</b>

<b>  public Alpha(string n) { name = n; }</b>

<b>  public string GetName() { return name; }</b>

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

<b>}</b>

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

<b>  public Beta(string n) : base(n) { }</b>

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

<b>}</b>

<b>class VarianceDemo {</b>

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

<b>    // Создать ссылку из интерфейса IMyCoVarGenIF на объект типа MyClass&lt;Alpha&gt;.</b>

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

<b>    IMyCoVarGenIF&lt;Alpha&gt; AlphaRef =</b>