c# - 这个协方差相关代码背后的意义是什么?
问题描述
我一直在阅读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);
第一行出现编译时错误,表示它无法转换Bear
为Animal
. 但是第二行是正确的并且工作正常。由于我是这个话题的新手,我无法理解这两条线之间的差异,我认为它们都接受了Stack<Animal>
,为什么我们需要使用条件泛型?
解决方案
Stack<Animal>
表示一堆任意Animal
类型的对象。
Stack<T> where T: Animal
表示单一类型的堆栈,只要该类型继承自Animal
.
您不能使用 aStack<Bear>
代替声明为的参数Stack<Animal>
,因为如果可以,则该方法可以将 a 压入Fish
熊堆栈。当使用Bear
s 的堆栈的方法将其从堆栈中弹出时,想象一下它从一条鱼中弹出时的惊讶!
另一方面,第二种方法是generic,这意味着它可以接受任何类型的堆栈,只要该类型继承自Animal
So 如果该方法获得 a Stack<Bear>
,它只能将另一个压入Bear
堆栈。尝试推送 aFish
将是运行时错误。
推荐阅读
- javascript - Angular Firebase 期望验证器返回 Promise 或 Observable
- c - 通过将二进制文件反转为源代码来对二进制文件进行模糊测试怎么样?
- ansible - 当 Ansible 控制器在 AWS VM 上时,是否可以从我的 mac 运行剧本?
- c# - Visual Studio 2019 WPF 设计器不会显示自定义控件
- java - Java 8 - 生成列表的幂集
- javascript - 如何使用 ANTd 在 React 中创建动态表单输入字段
- javascript - 相同的代码在不同的 IDE 中不起作用 - html,css
- python - 如何从python中的字母数字字符串中删除数字
- asp.net-mvc - 更新前的 asp.net mvc Kendo Grid 确认对话框
- excel - Excel - 添加与名称相关的所有分数