Tiger 是Animal,所以它可以做任何Animal 可以做的事情。如果我有一个要求Animal 的方法,我也可以传入Tiger。
协方差 - 传递更具体的类型参数
这是你最熟悉的方向。我可以在任何需要IEnumerable<Animal> 的地方传递IEnumerable<Tiger>。
static void ListAnimals(IEnumerable<Animal> animals)
{
}
List<Tiger> tigers = new List<Tiger>();
ListAnimals(tigers);
逆变 - 传递更一般的类型参数。
“对立”意味着这“违背”了正常的转换流程。这个比较棘手,因为在你看到它之前它似乎是违反直觉的。
假设我有一个函数,它期望一个 IComparer<Tiger> 和两只老虎进行比较。逆变说我也可以传入更通用的IComparer<Animal>,因为它也可以比较两只老虎(因为老虎是动物)。它以更一般的方式比较它们,但这仍然是类型安全的。
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());
请注意,这也适用于委托。我可以将Action<Animal> 传递给需要Action<Tiger> 的函数,因为Tiger 对象也可以安全地传递给Action<Animal> 委托。