Podría alguien darme ejemplos simples de C# de convarianza, contravariancia, invarianza y contrainvarianza (si tal cosa existe).
No tengo idea de qué significa "contra-invariante". El resto es fácil.
Aquí está un ejemplo de la covarianza:
void FeedTheAnimals(IEnumerable<Animal> animals)
{
foreach(Animal animal in animals)
animal.Feed();
}
...
List<Giraffe> giraffes = ...;
FeedTheAnimals(giraffes);
La interfaz IEnumerable<T>
es covariante. El hecho de que Jirafa sea convertible en Animal implica que IEnumerable<Giraffe>
es convertible a IEnumerable<Animal>
. Desde List<Giraffe>
implementa IEnumerable<Giraffe>
este código tiene éxito en C# 4; hubiera fallado en C# 3 porque la covarianza en IEnumerable<T>
no funcionó en C# 3.
Esto debería tener sentido. Una secuencia de jirafas se puede tratar como una secuencia de animales.
He aquí un ejemplo de contravarianza:
void DoSomethingToAFrog(Action<Frog> action, Frog frog)
{
action(frog);
}
...
Action<Animal> feed = animal=>{animal.Feed();}
DoSomethingToAFrog(feed, new Frog());
El delegado Action<T>
es contravariante. El hecho de que Frog sea convertible en Animal implica que Action<Animal>
es convertible a Action<Frog>
. Observe cómo esta relación es dirección opuesta de la covariante; es por eso que es la variante "contra". Debido a la convertibilidad, este código tiene éxito; hubiera fallado en C# 3.
Esto debería tener sentido. La acción puede tomar cualquier Animal; necesitamos una acción que pueda tomar cualquier Rana, y una acción que pueda tomar cualquier Animal seguramente también puede tomar cualquier Rana.
Un ejemplo de invariancia:
void ReadAndWrite(IList<Mammal> mammals)
{
Mammal mammal = mammals[0];
mammals[0] = new Tiger();
}
¿Podemos pasar una IList<Giraffe>
a esta cosa? No, porque alguien va a escribir un tigre en él, y un tigre no puede estar en una lista de jirafas. ¿Podemos pasar un IList<Animal>
en esto? No, porque vamos a leer un mamífero y una lista de animales podría contener una rana. IList<T>
es invariante. Solo se puede usar como lo que realmente es.
Para algunas consideraciones adicionales sobre el diseño de esta característica, vea mi serie de artículos sobre cómo lo diseñamos y construimos.
http://blogs.msdn.com/b/ericlippert/archive/tags/covariance+and+contravariance/
Alguien dio emitan un objeto a 'System.Object' como un ejemplo de covarianza? Eso ni siquiera está bien. –
Lo tomé como que significa pasar algún tipo de objeto (con algún tipo específico, más derivado) en lugar de 'System.Object', no necesariamente convertir 'object' en' System.Object', lo que sería inútil. –
_Variance_ no se debe confundir con _casting_, no son lo mismo. Ver: [Diferencia entre covarianza y upcasting] (http://stackoverflow.com/a/6707697/949681). – Pressacco