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