Страница 300 из 502
<b> public override string ToString() {</b>
<b> return "Это объект класса Alpha.";</b>
<b> }</b>
<b> // ...</b>
<b>}</b>
<b>class Beta : Alpha {</b>
<b> public override string ToString() {</b>
<b> return "Это объект класса Beta.";</b>
<b> }</b>
<b> // ...</b>
<b>}</b>
Ради большей наглядности классы Alpha и Beta несколько отличаются от аналогичных классов из предыдущего примера применения ковариантности. Обратите также внимание на то, что метод ToString() переопределяется таким образом, чтобы возвращать тип объекта.
С учетом всего изложенного выше, следующая последовательность операций будет считаться вполне допустимой.
<b>// Создать ссылку из интерфейса IMyContraVarGenIF<Alpha></b>
<b>//на объект типа MyClass<Alpha>.</b>
<b>// Это вполне допустимо как при наличии контравариантности, так и без нее.</b>
<b> IMyContraVarGenIF<Alpha> AlphaRef = new MyClass<Alpha>();</b>
<b>// Создать ссылку из интерфейса IMyContraVarGenIF<beta></b>
<b>// на объект типа MyClass<Beta>.</b>
<b>//И это вполне допустимо как при наличии контравариантности, так и без нее.</b>
<b>IMyContraVarGenIF<Beta> BetaRef = new MyClass<Beta>();</b>
<b>// Создать ссылку из интерфейса IMyContraVarGenIF<beta></b>
<b>// на объект типа MyClass<Alpha>.</b>
<b>// *** Это вполне допустимо благодаря контравариантности. ***</b>
<b>IMyContraVarGenIF<Beta> BetaRef2 = new MyClass<Alpha>();</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>
Прежде всего, обратите внимание на создание двух переменных ссылочного типа IMyContraVarGenIF, которым присваиваются ссылки на объекты класса MyClass, где параметры типа совпадают с аналогичными параметрами в интерфейсных ссылках. В первом случае используется параметр типа Alpha, а во втором — параметр типа Beta. Эти объявления не требуют контравариантности и допустимы в любом случае.
Далее создается переменная ссылочного типа IMyContraVarGenIF<Beta>, но на этот раз ей присваивается ссылка на объект класса MyClass<Alpha>. Эта операция вполне допустима, поскольку обобщенный тип Т объявлен как контравариантный.
Как и следовало ожидать, следующая строка, в которой вызывается метод BetaRef.Show() с аргументом Beta, является вполне допустимой. Ведь Beta — это обобщенный тип Т в классе MyClass<Beta> и в то же время аргумент в методе Show().
В следующей строке переменная AlphaRef присваивается переменной BetaRef. Эта операция вполне допустима лишь в силу контравариантности. В данном случае переменная относится к типу MyClass<Beta>, а переменная AlphaRef — к типу MyClass<Alpha>. Но поскольку Alpha является базовым классом для класса Beta, то такое преобразование типов оказывается допустимым благодаря контравариантности. Для того чтобы убедиться в необходимости контравариантности в рассматриваемом здесь примере, попробуйте удалить ключевое слово in из объявления обобщенного типа Т в интерфейсе IMyContraVarGenIF, а затем попытайтесь скомпилировать приведенный выше код еще раз. В результате появятся ошибки компиляции.
Ради большей наглядности примера вся рассмотренная выше последовательность операций собрана ниже в единую программу.
<b>// Продемонстрировать контравариантность в обобщенном интерфейсе,</b>
<b>using System;</b>
<b>// Это обобщенный интерфейс, поддерживающий контравариантность.</b>
<b>public interface IMyContraVarGenIF<in T> {</b>
<b> void Show(T obj);</b>
<b>}</b>
<b>// Реализовать интерфейс IMyContraVarGenIF.</b>
<b>class MyClass<T> : IMyContraVarGenIF<T> {</b>
<b> public void Show(T x) {</b>
<b> Console.WriteLine(x);</b>
<b> }</b>
<b>}</b>
<b>// Создать простую иерархию классов,</b>
<b>class Alpha {</b>
<b> public override string ToString() {</b>