2010-10-27 23 views
14

En el siguiente código:Pregunta sobre C# covarianza

interface I1 { } 
class CI1: I1 { } 

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

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

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

soy capaz de asignar mi "listOfCI1" a un IEnumerable<I1> (debido a la covarianza)

Pero por qué no soy capaz de asignar a un IList<I1>? Por lo demás, no puede ni siquiera hacer lo siguiente:

List<I1> listOfI12 = listOfCI1; 

No debe covarianza me permite asignar un tipo derivado a un tipo base?

Respuesta

24

En pocas palabras, IList<T> no es covariante, mientras que IEnumerable<T> es. He aquí por qué ...

Suponer IList<T>fue covariant. El código siguiente claramente no es seguro para tipos ... pero ¿dónde quieres que sea el error?

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 

Para un montón de detalles sobre varianza, ver Eric Lippert de blog post series en él, o ver el video de mi charla sobre la varianza de NDC.

Básicamente, la variación solo se permite donde se garantiza que es segura (y de forma que se preserve la representación, por lo que no se puede convertir IEnumerable<int> en IEnumerable<object> - la conversión de boxeo no conserva la representación).

+0

Btw, esa charla fue genial. –

+0

@Arnis: Gracias - Lo disfruté yo mismo, incluso si no pude mostrar el video de Hokey Cokey que había grabado ... –

+2

Jon, también lo hizo el equipo de BCL (IEnumerable : IEnumerable), porque IEnumerable no le permite agregar ningún miembro nuevo (es decir, es inmutable), lo que lo hace seguro. Pero, por otro lado, no se agregó "out" en IList porque es mutable (¿es posible agregar una implementación diferente a la lista subyacente?) –

3

De lo contrario, podría entonces añadir una implementación diferente de I1 a una lista que sólo debe contener C1 s.

1

IList<T> interfaz no es covariante.

5

declaraciones Comparar (MSDN)

public interface IEnumerable<out T> : IEnumerable 

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

que ver esa palabra mágica out? Esto significa que la covarianza está activada.

+3

Más específicamente, significa que 'IEnumerable ' es covariante * para 'T' *. Una interfaz puede ser una variante en algunos parámetros de tipo pero no en otros. –