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?

+6
source share
1 answer

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.

+3
source

All Articles