2012-09-14 24 views
15

Duplicar posible:
Why was IEnumerable<T> made covariant in C# 4?Por qué IEnumerable <T> se define como IEnumerable <out T>, no IEnumerable <T>

estaba tomando una mirada en MSDN para IEnumerable<T> definición de interfaz, y veo:

public interface IEnumerable<out T> : IEnumerable 

Me preguntaba por qué T se define como out, ¿por qué no?

public interface IEnumerable<T> : IEnumerable 

¿Cuál es la razón de esto?

+0

porque la interfaz es covariante – Jodrell

+1

vistazo aquí http://stackoverflow.com/questions/6732299/why-was-ienumerablet-made-covariant-in-c-sharp-4 – Likurg

+0

[Covarianza y contravarianza] (http://msdn.microsoft.com/en-us/library/ee207183) – jrummell

Respuesta

20

Más información se puede encontrar here.

El out hace que el parámetro de tipo sea covariante. Es decir, puede usar el tipo o cualquier tipo derivado. Tenga en cuenta que out solo funciona de esta forma con genéricos, tiene un significado diferente cuando se usa en firmas de métodos (aunque probablemente ya lo sabía).

Aquí está el ejemplo tomado de la referenced page:

// Covariant interface. 
interface ICovariant<out R> { } 

// Extending covariant interface. 
interface IExtCovariant<out R> : ICovariant<R> { } 

// Implementing covariant interface. 
class Sample<R> : ICovariant<R> { } 

class Program 
{ 
    static void Test() 
    { 
     ICovariant<Object> iobj = new Sample<Object>(); 
     ICovariant<String> istr = new Sample<String>(); 

     // You can assign istr to iobj because 
     // the ICovariant interface is covariant. 
     iobj = istr; 
    } 
} 

Como se puede ver, el out en la firma interfaz permite asignar una ICovariant<String> a una variable ICovariant<Object>, como se deriva de StringObject. Sin la palabra clave out, no podría hacer esto, ya que los tipos serían diferentes.

Puede leer más sobre la covarianza (y la contravariancia relacionada) here.

Como otras respuestas han señalado, IEnumerable sólo fue covariante en .NET 4. Tratar de escribir código, tales como:

IEnumerable<Object> strings = new List<string>(); 

compilará en .NET 4 y versiones posteriores, pero no en las versiones anteriores .

6

Covariance. Esto permite asignar a una colección elementos de un tipo más específico o derivado que los especificados en su parámetro genérico.

IEnumerable<T> no siempre fue covariante; esto era nuevo en .NET 4, y el motivo del cambio se explica en here.

0

Para lograr esto:

class Base {} 
class Derived : Base {} 

List<Derived> list = new List<Derived>(); 
IEnumerable<Base> sequence = list; 
4

El tipo out parámetro especificador indica covarianza.

En la práctica,

Si defino dos interfaces.

ISomeInterface<T> 
{ 
} 

ISomeCovariantInterface<out T> 
{ 
} 

Luego, los implemento así.

SomeClass<T> : ISomeInterface<T>, ISomeCovariantInterface<T> 
{ 
} 

Entonces intento compilar este código,

ISomeCovariantInterface<object> = new SomeClass<string>(); // works 
ISomeInterface<object> = new SomeClass<string>(); // fails 

El es porque la interfaz covariante permite casos más derivados, donde como, la interfaz estándar no lo hace.

+0

+1 Creo que esta es la respuesta de nivel de introducción más clara. – TarkaDaal

Cuestiones relacionadas