0

I am wondering how an array has different behaviour to List<T>, both which implement IList, where the array appears to be getting around IList's non-covariant nature (it is not defined as IList<out T>), when assigning to IList<IPerson>. In the below example all assignments are ok except for 'people3'. Why does the assignment work in the case of 'people4' for personArray?

public interface IPerson { }
public class Person : IPerson { }

var personList = new List<Person>();
var personArray = new Person[0];

IList<Person> people1 = personList;
IList<Person> people2 = personArray;
IList<IPerson> people3 = personList;
IList<IPerson> people4 = personArray;
CRice
  • 12,279
  • 7
  • 57
  • 84
  • [Not *totally* a duplicate](http://stackoverflow.com/questions/3516619/why-are-c-sharp-arrays-covariant-and-what-benefits-does-it-bring) so I won't hammer it. – Rawling Sep 19 '14 at 12:41
  • 1
    Somehow my attempts to find related questions missed that one – CRice Sep 19 '14 at 12:42
  • http://blogs.msdn.com/b/ericlippert/archive/2007/10/17/covariance-and-contravariance-in-c-part-two-array-covariance.aspx explains... – CRice Sep 19 '14 at 12:58

2 Answers2

2

It's because that kind of covariance is a bad thing and C# only supports it with arrays because Java supports it.

This gives a runtime error

        object[] myArray = new string[1];
        myArray[0] = 1;

This gives a compile time error

        List<object> myList = new List<string>(1);
        myList[0] = 1;
Dallas
  • 78
  • 1
  • 7
  • So do you think it 'is a bad thing' purely because of possible runtime assignment errors? Otherwise I like the free behaviour in the case of compatible sub class / base class. – CRice Jul 22 '16 at 05:13
  • In your original example you created a List. If you intended it to be a List then you should have done that originally. By converting it to a List you are allowing something other than a Person to be added to the list. This is prevented at compile time with lists, and at run time with arrays. You do not actually have any more flexibility. – Dallas Jul 30 '16 at 08:31
  • In that case I'm now inclined to use List, IReadOnlyList, IReadOnlyCollection. :) – CRice Aug 01 '16 at 00:24
0

If T:U, an instance to a T[] may be cast to IList<U>, but even though IList<T>.IsReadOnly will be false, IList<U>.IsReadOnly will return true. Note that even though IList<U>.IsReadOnly returns true, attempts to write to the IList<U> may still succeed if the particular item being written happens to satisfy type T. There is no way I know of to ascertain whether a particular instance identified by a U may be stored into an ILIst<T> except by trying it and observing if an exception occurs.

supercat
  • 77,689
  • 9
  • 166
  • 211