-3

我今天正在阅读协变和逆变,我遇到了一篇关于堆栈交换的帖子,其中 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 的值设置为香蕉列表,该列表与水果列表协变,然后尝试将 Apple 添加到类型为真的集合中List<Banana>吗?

感谢下面的马特。记住您正在处理引用类型会有所帮助。永远对此投反对票。

4

1 回答 1

1

我认为您缺少的是,当您在第一个示例中执行以下操作时:

List<Fruit> fruitBowl = bunchOfBananas;

没有将副本复制bunchOfBananasList<Fruit>. 相反,您正在创建对一堆香蕉的引用,并且该引用可用于添加任何种类的水果。

因此,当您这样做时:

fruitBowl.Add(new Apple());

您不会将苹果添加到水果列表中;你会在 中添加一个苹果List<Banana> bunchOfBananas,这显然是一件坏事。

于 2013-05-01T13:10:36.807 回答