今天我正在阅读关于协方差和逆变的文章,我遇到了一个关于堆栈交换的帖子,其中Jon Skeet解释了班级的不变性。他用了一个水果的例子,为什么在这个级别允许协方差会是一件坏事:
//Bad
List<Banana> bunchOfBananas = new List<Banana>();
// This would be valid if List<T> were covariant in T
List<Fruit> fruitBowl = bunchOfBananas;
fruitBowl.Add(new Apple());
Banana banana = bunchOfBananas[0];
那么,如何使用Fruit列表来添加从Fruit继承的类的实例呢?例如:
//Good
List<Fruit> fruitBowl = new List<Fruit>();
fruitBowl.Add(new Apple());
fruitBowl.Add(new Banana());
我过去做过这个,它总是表现得像预期的那样。为什么CLR看不到fruitBowl的类型?是因为你首先将fruitBowl的值设置为香蕉列表,它与Fruit列表协变,然后然后尝试将Apple添加到类型为{{1}的集合中}?
感谢下面的马特。它有助于记住您正在处理引用类型。永远地投下这个。
答案 0 :(得分:1)
我认为你缺少的是当你第一个例子时:
List<Fruit> fruitBowl = bunchOfBananas;
您不将bunchOfBananas
的副本复制到List<Fruit>
。相反,您正在创建对一堆香蕉的引用,并且该引用可用于添加任何类型的水果。
因此当你这样做时:
fruitBowl.Add(new Apple());
你不会将苹果添加到水果列表中;你要在List<Banana> bunchOfBananas
添加一个苹果,这显然是一件坏事。