Un Tiger
es un Animal
por lo que se puede hacer cualquier cosa que un Animal
puede hacer. Si tengo un método que pide un Animal
, también puedo pasar un Tiger
.
covarianza - Pasar un argumento de tipo más específico
Ésta es la dirección que está más familiarizado. Puedo pasar un IEnumerable<Tiger>
en cualquier lugar que espere un IEnumerable<Animal>
.
static void ListAnimals(IEnumerable<Animal> animals)
{
}
List<Tiger> tigers = new List<Tiger>();
ListAnimals(tigers);
contravarianza - Pasar un argumento de tipo más general.
El 'contra' implica que esto va 'contra' el flujo de conversión normal. Este es más complicado porque parece contraintuitivo hasta que lo ves en acción.
Supongo que tengo una función que espera que se comparen un IComparer<Tiger>
y dos tigres. La contradicción dice que también puedo pasar en el más general IComparer<Animal>
porque puede también comparar dos tigres (ya que un Tigre ES un animal). Los compara de una manera más general, pero esto todavía es seguro.
static void CompareTigers(IComparer<Tiger> comparer, Tiger tiger1, Tiger tiger2)
{
comparer.Compare(tiger1, tiger2);
}
// normal - a tiger comparer can compare two tigers
IComparer<Tiger> tigerComparer = null;
CompareTigers(tigerComparer, new Tiger(), new Tiger());
// contravariance - an animal comparer can ALSO compare two tigers
IComparer<Animal> animalComparer = null;
CompareTigers(animalComparer, new Tiger(), new Tiger());
Tenga en cuenta que esto también funciona con los delegados. Puedo pasar un Action<Animal>
en una función que espera un Action<Tiger>
porque los objetos Tiger
también se pueden pasar de manera segura al delegado Action<Animal>
.
¿Qué es el Canal 9? –
http://channel9.msdn.com/ - Una colección de videos sobre marcos de desarrollo de microsoft, y mucho más :) – cwap
Sí, es como un podcast, tiene algunos C# vids muy buenos con Anders, etc. –