c# - 为什么 Animals[] animals = new Cat[5] 编译,但 List<Animal> animals = new List<Cat>() 不编译?

标签 c# arrays generics covariance

在他的C# 深入一书中,Jon Skeet 试图回答以下问题:

Why can't I convert List<string> to List<object>?

为了解释它,他从一个代码片段开始,其中包括以下两行:

Animal[] animals = new Cat[5]; //Ok. Compiles fine!            
List<Animal> animals = new List<Cat>(); //Compilation error!

正如评论所读,第一个compiles fine , 但第二个给出 compilation error .我真的不明白原因。 Jon Skeet 对此解释说,第一个编译是因为在 .NET 中,数组是协变的,而第二个不编译是因为泛型不是协变的(它们是不变的)。此外,数组在 .NET 中是协变的,因为数组在 Java 中是协变的,而 .NET 使其类似于 Java。

我对这个简短的回答并不完全满意。我想更详细地了解它,深入了解编译器如何处理差异,以及它如何生成 IL 等等。

此外,如果我写(摘自本书本身):

Animal[] animals = new Cat[5]; //Ok. Compiles fine!
animals.Add(new Turtle()); //this too compiles fine!

它编译正常,但在运行时失败。如果它必须在运行时失败(这意味着我写的东西没有意义),那么为什么它首先要编译?我可以使用实例 animals 吗?在我的代码中,并且运行时也没有运行时错误?

最佳答案

数组在 .NET 中有一段奇怪的历史。 2.0 版的 CLR 和 C# 4.0 中的语言添加了对变体的适当支持。然而,数组始终具有协变行为。

Eric Lippert 在 blog post 中详细介绍了这一点.

有趣的一点:

Ever since C# 1.0, arrays where the element type is a reference type are covariant. This is perfectly legal:

Animal[] animals = new Giraffe[10];

Since Giraffe is smaller than Animal, and “make an array of” is a covariant operation on types, Giraffe[] is smaller than Animal[], so an instance fits into that variable.

Unfortunately, this particular kind of covariance is broken. It was added to the CLR because Java requires it and the CLR designers wanted to be able to support Java-like languages. We then up and added it to C# because it was in the CLR. This decision was quite controversial at the time and I am not very happy about it, but there’s nothing we can do about it now.

强调是我自己加的。

关于c# - 为什么 Animals[] animals = new Cat[5] 编译,但 List<Animal> animals = new List<Cat>() 不编译?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7588183/

相关文章:

java - 通配符和通用类/方法声明的不同政策。为什么?

c# - 关于 StructLayoutAttribute 中 sizeof(T) 的 CS0233 有什么替代方案吗?

c# - 在 "delegate"中记录每个方法

c# - C# 中的高性能乘法/求值

c# - 使用 ToList() 和 .AsQueryable() 连接两个不同的数据库上下文有什么区别?

javascript - 如何循环对象数组来求解简单的求和

java - 使用泛型参数列表的泛型方法声明

c# - 如何将带小数的数字的外国字符串表示形式转换为 double ?

javascript - 为什么键值对中的 ":"在控制台中打印时转换为 =。

javascript - 将数组传递给 JavaScript 过滤器函数