【问题标题】:Why List<Parent> permits adding new Child but not assigning from List<Child>为什么 List<Parent> 允许添加新的 Child 但不能从 List<Child> 分配
【发布时间】:2021-10-22 16:22:32
【问题描述】:

这可能是重复的。但经过一天的研究,我希望你能宽大处理。 这是一个关于协方差的问题。

为什么我可以这样做?

List<Animal> allAnimals = new List<Animal>();
allAnimals.Add(new Dog());
allAnimals.Add(new Cat());

但不能这样做?

List<Dog> aBunchOfDogs = new List<Dog>();
allAnimals = aBunchOfDogs;

我已经阅读了一些关于协方差的讨论。

"Covariance in C#"

"Converting lists to interface lists"

"Casting list to interface list"

我的理解是,我不能将狗列表添加到动物列表中,因为这样我可以将猫添加到动物列表中,这很危险。但是将一只猫或一只狗的单个实例添加到动物列表中同样危险,不是吗? 在我看来,C# 还没有决定是否信任我。

【问题讨论】:

  • allAnimals = aBunchOfDogs:现在allAnimals 是对aBunchOfDogs 所引用的同一底层列表的引用,即List&lt;Dog&gt;。现在做allAnimals.Add(new Cat())——哎呀!我们在List&lt;Dog&gt; 中添加了CataBunchOfAnimals[^1]aBunchOfDogs[^1] 现在都返回 Cat。这是不对的!
  • 你不能做类似allAnimals = aBunchOfDogs as List&lt;Animal&gt;;的事情吗?
  • @Rafalon 你可以试试,不过allAnimals 会是null...
  • @canton7 刚刚在.net fiddle中尝试过,结果编译错误,所以我们甚至无法尝试。但是我们可以allAnimals = new List&lt;Animal&gt;(aBunchOfDogs);
  • 男人。我想我全都错了。感谢你的帮助。我的大脑仍在试图解决这个问题,但你的 cmets 会做到这一点。这说得通。我可以将一只猫或一只狗或一群狗添加到动物列表中,因为我只能将动物列表用作动物。但是我不能将动物列表作为对狗列表的引用。因为那时我可以通过添加一只猫来打破狗名单。非常感谢!

标签: c# list casting covariance


【解决方案1】:

假设您了解为什么可以将 DogCat 实例传递给接受 Animal 的方法,这就是不允许后一个示例的原因:

List<Dog> aBunchOfDogs = new List<Dog>();
allAnimals = aBunchOfDogs;
allAnimals.Add(new Cat()); // Fine because allAnimals is List<Animal>

foreach (var dog in aBunchOfDogs)
{
    dog.Woof(); // The Cat can't woof
}

【讨论】:

  • 很好的例子!容易理解!
  • 谢谢乔纳森。我真的很难理解,但它开始变得有意义了。我认为不知不觉我认为“allAnimals = aBunchOfDogs”的意思是“allAnimals = new List(aBunchOfDogs)”,这当然是完全错误的。
  • @Capricornum 是的,这里的实例(运行时)类型永远是List&lt;Dog&gt;;如果您能够将其分配给仅在编译时检查的List&lt;Animal&gt; 变量;运行时类型永远不会改变。
猜你喜欢
  • 2010-11-13
  • 2011-08-11
  • 1970-01-01
  • 1970-01-01
  • 2019-07-10
  • 1970-01-01
  • 1970-01-01
  • 2015-10-14
相关资源
最近更新 更多