List, Array, and IEnumerable Covariance

I will start with a few postulates to better explain the context of my question:

Array covariance

Postulate 1.1

An array of type value is not covariant. int[] cannot pass for object[] .

Postulate 1.2

An array of reference type is covariant with a valid IEnumerable . string[] may pass for IEnumerable<object> ).

Postulate 1.3

An array of a reference type is covariant with a valid covariant array. string[] may pass for object[] .

List covariance

Postulate 2.1 (same as 1.1)

A value type list is not covariant. List<int> cannot pass for List<object> .

Postulate 2.2 (the same as 1.2)

A reference type list is covariant with a valid IEnumerable . List<string> may pass for IEnumerable<object> ).

Postulate 2.3 (differs from 1.3)

A reference type list is not covariant with a valid List covariant. List<string> cannot pass for List<object> ).


My question concerns postulates 1.3, 2.2 and 2.3. In particular:

  • Why does string[] pass for object[] , but List<string> not for List<object> ?
  • Why does List<string> pass for IEnumerable<object> but not for List<object> ?
+6
source share
2 answers

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 recognized as an error and has been present since version 1.

Since the collection cannot be modified using the IEnumerable<T> interface, it is safe to print a List<string> as an IEnumerable<object> .

+13
source

Arrays are covariant, but a System.Int32[] does not contain references to things that are obtained from System.Object . In the .NET runtime, each value type definition actually defines two types of things: the type of the heap object and the type of the value (storage type). The type of heap object obtained from System.Object ; the type of storage location is implicitly converted to the type of the heap object (which, in turn, comes from System.Object ), but by itself is not inferred from System.Object and nothing else. Although all arrays, including System.Int32[] , are heap object types, the individual System.Int32[] elements are instances of the storage location type.

The reason a String[] can be passed to code waiting for Object[] is because the former contains "references to instances of a heap type object obtained from the String type," and the latter is similar for the Object type. Since String comes from Object , a reference to a heap object of the type derived from String will also be a reference to a heap object that comes from Object , and a String[] will contain references to heaps of objects that derive from Object - exactly what expect code from Object[] . On the contrary, since a int[] [ie System.Int32[] ] does not contain references to heap instances of type Int32 ; its contents will not meet the expectations of the code that Object[] expects.

-1
source

Source: https://habr.com/ru/post/947094/


All Articles