Вопрос о ковариантности C # - PullRequest
15 голосов
/ 27 октября 2010

В коде ниже:

interface I1 { }
class CI1: I1 { }

List<CI1> listOfCI1 = new List<CI1>();

IEnumerable<I1> enumerableOfI1 = listOfCI1; //this works

IList<I1> listofI1 = listOfCI1; //this does not

Я могу назначить свой "listOfCI1" для IEnumerable<I1> (из-за ковариации)

Но почему я не могу присвоить его IList<I1>? В связи с этим я даже не могу сделать следующее:

List<I1> listOfI12 = listOfCI1;

Разве ковариация не позволяет мне назначать производный тип базовому типу?

Ответы [ 4 ]

24 голосов
/ 27 октября 2010

Проще говоря, IList<T> не является ковариантным, тогда как IEnumerable<T> есть. И вот почему ...

Предположим, IList<T> было ковариантным. Приведенный ниже код явно не является типобезопасным ... но где бы вы хотели, чтобы ошибка была?

IList<Apple> apples = new List<Apple>();
IList<Fruit> fruitBasket = apples;
fruitBasket.Add(new Banana()); // Aargh! Added a Banana to a bunch of Apples!
Apple apple = apples[0]; // This should be okay, but wouldn't be

Для лотов подробностей по дисперсии, см. серию постов Эрика Липперта в блоге или посмотрите видео моего разговора об отклонениях от NDC. 1017 *

По сути, дисперсия допускается только в тех случаях, когда она гарантированно безопасна (и с сохранением представления, поэтому вы не можете преобразовать IEnumerable<int> в IEnumerable<object> - преобразование в бокс не сохраняет представление) .

5 голосов
/ 27 октября 2010

Сравнить объявления (MSDN)

public interface IEnumerable<out T> : IEnumerable

public interface IList<T> : ICollection<T>, IEnumerable<T>, IEnumerable

Вы видите это волшебное слово out? Это означает, что ковариация включена.

3 голосов
/ 27 октября 2010

Нет.

В противном случае вы сможете добавить другую реализацию I1 в список, который должен содержать только C1 с.

1 голос
/ 27 октября 2010

IList<T> интерфейс не является ковариантным.

...