Reputation: 25214
I'll start with several postulates to better explain the context of my question:
An array of a value type is not covariant. int[]
cannot pass for object[]
.
An array of a reference type is covariant with a valid IEnumerable
. string[]
can pass for IEnumerable<object>
).
An array of a reference type is covariant with a valid covariant array. string[]
can pass for object[]
.
A list of a value type is not covariant. List<int>
cannot pass for List<object>
.
A list of a reference type is covariant with a valid IEnumerable
. List<string>
can pass for IEnumerable<object>
).
A list of a reference type is not covariant with a valid covariant List
. List<string>
cannot pass for List<object>
).
My question concerns postulates 1.3, 2.2 and 2.3. Specifically:
string[]
pass for object[]
, but List<string>
not for List<object>
?List<string>
pass for IEnumerable<object>
but not for List<object>
?Upvotes: 6
Views: 1465
Reputation: 81217
Arrays are covariant, but a System.Int32[]
does not hold references to things which are derived from 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. The heap object type is derived from 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. Although all arrays, including System.Int32[]
are heap-object types, the individual elements of a System.Int32[]
are instances of the storage location type.
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
. 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[]
. By contrast, because an int[]
[i.e. 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[]
.
Upvotes: -1
Reputation: 144196
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.
Since the collection cannot be modified through the IEnumerable<T>
interface, it is safe to type a List<string>
as an IEnumerable<object>
.
Upvotes: 13