2010-10-27 2 views
14

В приведенном ниже коде:Вопрос о C# ковариации

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> (вследствие ковариации)

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

List<I1> listOfI12 = listOfCI1; 

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

ответ

24

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

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

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 

Для много деталей о дисперсии см Эрик Липперта blog post series на нем, или смотреть video моего разговора о дисперсии НДЦ.

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

+0

Btw, этот разговор был замечательный. –

+0

@Arnis: Спасибо. Мне понравилось это, даже если я не смог показать видео Hokey Cokey, которое записал ... –

+2

Jon, так и команда BCL добавила (IEnumerable : IEnumerable), потому что IEnumerable не позволяет добавлять новые члены (т. Е. Его непреложный), что делает его безопасным. Но с другой стороны не добавили «out» на IList , потому что он изменен (позволяет добавить другую реализацию в базовый список?) –

3

No.

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

1

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

5

Сравнить декларации (MSDN)

public interface IEnumerable<out T> : IEnumerable 

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

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

+3

В частности, это означает, что 'IEnumerable ' является ковариантным * для 'T' *. Интерфейс может быть вариантом в некоторых параметрах типа, но не в других. –