Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

List, array and IEnumerable covariance

I'll start with several postulates to better explain the context of my question:

Array Covariance

Postulate 1.1

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

Postulate 1.2

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

Postulate 1.3

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

List Covariance

Postulate 2.1 (same as 1.1)

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

Postulate 2.2 (same as 1.2)

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

Postulate 2.3 (different from 1.3)

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:

  1. Why can string[] pass for object[], but List<string> not for List<object>?
  2. Why can List<string> pass for IEnumerable<object> but not for List<object>?
like image 685
Levi Botelho Avatar asked Jun 12 '13 09:06

Levi Botelho


People also ask

Is IEnumerable covariant?

Several generic interfaces have covariant type parameters, for example, IEnumerable<T>, IEnumerator<T>, IQueryable<T>, and IGrouping<TKey,TElement>. All the type parameters of these interfaces are covariant, so the type parameters are used only for the return types of the members.

Why is IEnumerable covariant?

No, because covariance is only allowed on interfaces that return values of that type, but don't accept them.

What is difference between covariance and Contravariance?

In C#, covariance and contravariance enable implicit reference conversion for array types, delegate types, and generic type arguments. Covariance preserves assignment compatibility and contravariance reverses it.

What is array covariance?

Array covariance allows us to assign an array of a subtype of a class to a variable whose type is an array of the base type. 1. Dog[] dogs = new Terrier[3]; This can lead to a problem. What looks syntactically like an array of Dogs is really an array of Terriers.


1 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 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>.

like image 99
Lee Avatar answered Oct 03 '22 14:10

Lee