从uint []转换为int []的C#调用ToList()异常

前端之家收集整理的这篇文章主要介绍了从uint []转换为int []的C#调用ToList()异常前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我得到一个异常System.ArrayTypeMismatchException:源代码数组类型不能分配给此代码片段的目标数组类型:
var uints = GetArray();
if (uints is int[])
{
    var list = ((int[])uints).ToList(); // fails when call ToList()
}

private Array GetArray()
{
    var result = new uint[] { uint.MaxValue,2,3,4,5 };
    return result;
}

然后我在Why does “int[] is uint[] == true” in C#中诉诸Jon的答案,它告诉我,由于GetArray()返回一个Array,转换在运行时被推迟,CLR允许这种类型的int [](反之亦然)转换.如果我在转换后检查值,它实际上可以正常工作:

foreach (var i in ((int[])units))
{
    System.Console.WriteLine(i.GetType());
    System.Console.WriteLine(i);
}

我会得到:

System.Int32
-1
System.Int32
2
//skipped...

但是我有点困惑为什么在调用ToList()时会失败,因为下面的代码可以正常工作吗?

internal class Animal
{
}

internal class Cat : Animal
{
}

var cats = new Cat[] { new Cat(),new Cat() };
List<Animal> animals = ((Animal[])cats).ToList(); //no exception
这里发生了什么?我们从foreach循环开始,C#编译器优化它们,特别是当你使用数组时,它们基本上是(int i = 0; i< length; i){}的变化 - 所以
foreach (var i in ((int[])units))
{
    System.Console.WriteLine(i.GetType());
    System.Console.WriteLine(i);
}

不能信任,BTW foreach也可以执行对元素类型的转换,最好是尝试通用的Array.GetValue方法

int[] x = ((int[])uints);
Console.WriteLine(x.GetValue(0).GetType()); // System.UInt32

Console.WriteLine(x[0].GetType()); // System.Int32

所以即使访问x [0]可以返回已经转换的值,但是Array.GetValue返回已经有一个uint.

我们再做一个实验:

Console.WriteLine(x.GetType()); // System.UInt32[]

Console.WriteLine(uints.GetType()); // System.UInt32[]

Console.WriteLine(Object.ReferenceEquals(x,uints)); // True

这确保我们在var x =(int [])uints中的转换是一个NOP – 没有操作,它根本不做任何事情.特别是第三行显示我们得到完全相同的实例.

现在List constructor我们有线

_items = new T[count];
c.CopyTo(_items,0);

实际上抛出数组不匹配异常.

但是为什么这个例外不是早期抛出,当GetEnumerator()被调用时,我不知道自己,我预计会在行上抛出异常

x.GetEnumerator()

因为类型IEnumerable< int>和IEnumerable< uint>不兼容但没有 – 可能是因为.NET返回这里对于每个值类型数组都是相同的System.Array SZArrayEnumerator.

编辑:(以猫为例)
C#中的数组协方差保证我们可以将任何引用类型的数组分配给object [],并将Subclass []类型的数组分配给BaseClass [].值类型的情况是不同的,因为它们可以具有不同的大小和/或转换行为(uint vs int).

ToList使用内部的Array.Copy调用,当我们看到CRL:https://github.com/dotnet/coreclr/blob/32f0f9721afb584b4a14d69135bea7ddc129f755/src/classlibnative/bcltype/arraynative.cpp#L328中的Array.Copy实现时,我们看到只有当值类型具有由另一个util函数检查的兼容单位时,才能复制该数组https://github.com/dotnet/coreclr/blob/32f0f9721afb584b4a14d69135bea7ddc129f755/src/vm/invokeutil.h#L196

另一个问题是为什么它是这样实现的?

猜你在找的Windows相关文章