简体   繁体   English

列表,数组和IEnumerable协方差

[英]List, array and IEnumerable covariance

I'll start with several postulates to better explain the context of my question: 我将从几个假设开始,以更好地解释我的问题的背景:

Array Covariance 数组协方差

Postulate 1.1 假设1.1

An array of a value type is not covariant. 值类型的数组不是协变的。 int[] cannot pass for object[] . int[]无法传递object[]

Postulate 1.2 假设1.2

An array of a reference type is covariant with a valid IEnumerable . 引用类型的数组与有效的IEnumerable协变。 string[] can pass for IEnumerable<object> ). string[]可以传递给IEnumerable<object>

Postulate 1.3 假设1.3

An array of a reference type is covariant with a valid covariant array. 引用类型的数组与有效的协变数组协变。 string[] can pass for object[] . string[]可以传递给object[]

List Covariance 列出协方差

Postulate 2.1 (same as 1.1) 假设2.1(与1.1相同)

A list of a value type is not covariant. 值类型的列表不是协变的。 List<int> cannot pass for List<object> . List<int>无法传递List<object>

Postulate 2.2 (same as 1.2) 假设2.2(与1.2相同)

A list of a reference type is covariant with a valid IEnumerable . 引用类型的列表与有效的IEnumerable协变。 List<string> can pass for IEnumerable<object> ). List<string>可以传递给IEnumerable<object>

Postulate 2.3 (different from 1.3) 假设2.3(与1.3不同)

A list of a reference type is not covariant with a valid covariant List . 引用类型列表与有效协变List不协变。 List<string> cannot pass for List<object> ). List<string>无法传递List<object> )。


My question concerns postulates 1.3, 2.2 and 2.3. 我的问题涉及假设1.3,2.2和2.3。 Specifically: 特别:

  1. Why can string[] pass for object[] , but List<string> not for List<object> ? 为什么string[]传递给object[] ,但是List<string>不能传递给List<object>
  2. Why can List<string> pass for IEnumerable<object> but not for List<object> ? 为什么List<string>传递IEnumerable<object>而不能传递给List<object>

List covariance is unsafe: 列表协方差是不安全的:

List<string> strings = new List<string> { "a", "b", "c" };
List<object> objects = strings;
objects.Add(1);              //

Array covariance is also unsafe for the same reason: 由于同样的原因,数组协方差也是不安全的:

string[] strings = new[] { "a", "b", "c" };
object[] objects = strings;
objects[0] = 1;              //throws ArrayTypeMismatchException

array covariance in C# is recognised as a mistake , and has been present since version 1. C#中的数组协方差被认为是一个错误 ,并且自版本1以来一直存在。

Since the collection cannot be modified through the IEnumerable<T> interface, it is safe to type a List<string> as an IEnumerable<object> . 由于无法通过IEnumerable<T>接口修改集合,因此可以安全地将List<string>键入为IEnumerable<object>

Arrays are covariant, but a System.Int32[] does not hold references to things which are derived from System.Object . 数组是协变的,但System.Int32[]不保存对从System.Object派生的内容的引用。 Within the .NET runtime, each value-type definition actually defines two kinds of things: a heap object type and a value (storage location) type. 在.NET运行时中,每个值类型定义实际上定义了两种类型:堆对象类型和值(存储位置)类型。 The heap object type is derived from System.Object ; 堆对象类型派生自System.Object ; the storage location type is implicitly convertible to the heap object type (which in turn derives from System.Object ) but does not itself actually derive from System.Object nor anything else. 存储位置类型可以隐式转换为堆对象类型(后者又从System.Object派生)但实际上并不是从System.Object派生的,也不是其他任何东西。 Although all arrays, including System.Int32[] are heap-object types, the individual elements of a System.Int32[] are instances of the storage location type. 尽管所有数组(包括System.Int32[]都是堆对象类型),但System.Int32[]的各个元素都是存储位置类型的实例。

The reason that a String[] can be passed to code expecting an Object[] is that the former contains "references to heap-object instances of type derived from type String ", and the latter likewise for type Object . 可以将String[]传递给期望Object[]代码的原因是前者包含“对从类型String派生的类型的堆对象实例的引用”,后者同样适用于类型Object Since String derives from Object , a reference to a heap-object of a type derived from String will also be a reference to a heap object which derives from Object , and a String[] will contain references to heap objects which derive from Object --exactly what code would expect to read from an Object[] . 由于String从导出Object ,从派生的类型的一个堆对象的引用String也将是从派生的堆对象的引用Object ,和一个String[]将包含对从派生堆中的对象的引用Object -究竟是什么代码期望从Object[]读取。 By contrast, because an int[] [ie System.Int32[] ] does not contain references to heap-object instances of type Int32 , its contents will not conform to the expectations of code which is expecting Object[] . 相反,因为int[] [即System.Int32[] ]不包含对Int32类型的堆对象实例的引用,所以它的内容将不符合期望Object[]的代码的期望。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM