首页 > 解决方案 > 这个协方差相关代码背后的意义是什么?

问题描述

我一直在阅读O'REILLY 的一本名为 c# 7.0 in a Nutshell 的书,主题:Variance is not Automatic。有一个例子有 2 个类,Animal 和 Bear,其中 Animal>Bear:

public class Animal { }
public class Bear: Animal { }

还有这样一个类:

public class Stack<T>
{
    private int position;
    T[] data = new T[100];
    public void Push(T obj) => data[position++] = obj;
    public T Pop() => data[--position];
}

继续有 2 个版本的同一类:

public class ZooCleaner1
{
    public static void Wash(Stack<Animal> animals) { }
}

和:

public class ZooCleaner2
{
    public static void Wash<T>(Stack<T> animals) where T: Animal { }
}

它解释说,如果我尝试写:

ZooCleaner1.Wash(bears);
ZooCleaner2.Wash(bears);

第一行出现编译时错误,表示它无法转换BearAnimal. 但是第二行是正确的并且工作正常。由于我是这个话题的新手,我无法理解这两条线之间的差异,我认为它们都接受了Stack<Animal>,为什么我们需要使用条件泛型?

标签: c#genericscovariance

解决方案


Stack<Animal>表示一堆任意Animal类型的对象。 Stack<T> where T: Animal表示单一类型的堆栈,只要该类型继承自Animal.

您不能使用 aStack<Bear>代替声明为的参数Stack<Animal>,因为如果可以,则该方法可以将 a 压入Fish熊堆栈。当使用Bears 的堆栈的方法将其从堆栈中弹出时,想象一下它从一条鱼中弹出时的惊讶!

另一方面,第二种方法是generic,这意味着它可以接受任何类型的堆栈,只要该类型继承自AnimalSo 如果该方法获得 a Stack<Bear>,它只能将另一个压入Bear堆栈。尝试推送 aFish将是运行时错误。


推荐阅读