Why is IEnumerable <T> differentiated differently based on how I initialized the value?
I have code that takes a value (of an object of type) and tries to pass it to IEnumerable from int and uints, for example:
var idList = value as IEnumerable<int>; var uintList = value as IEnumerable<uint>; When the value is initialized as follows:
uint number = 1; object value = new []{ number }; both idList and uintList matter, but calling idList.ToList () results in an ArrayTypeMismatchException . However, when the value is generated using new List<uint>{ number } , idList is null as expected.
In addition, a call to var idList = value as IEnumerable<int>; in the direct window, VS 2015 returns null, as I would expect, even when this value was generated by the collection initializer.
.Net script reproducing the error here .
What's going on here?
I think that due to the unusual differences between how C # and CLR handle conversions between int and uint , as described in this answer . First of all, note that this code will not compile:
uint[] a1 = new[] { 1u }; var a2 = (int[])a1; Because C # doesn't think there is a cast. However, if you go as follows:
uint[] a1 = new[] { 1u }; var a2 = (int[]) (object) a1; Runtime will decide whether this actor is valid or not, and it (CLR) thinks differently and allows you to distinguish from uint[] to int[] (and vice versa), as described in the answer I linked.
But the same is not true for List<int> and List<uint> - they are not processed by the CLR in a special way and as such cannot be between each other.
So in your case uint[] can be added to int[] and int[] implements IEnumerable<int> , so your idList not null. This is not true for lists - hence your problem.
As for why ToList fails in the first case, it is because inside it does something like this:
uint[] a1 = new[] { 1u }; var a2 = (int[]) (object) a1; // ToList copies contents to new array int[] copy = new int[a2.Length]; Array.Copy(a2, copy, a2.Length); And Array.Copy checks directly if the type of elements in one array is compatible with the type of elements in another array.