微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

从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

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

原文地址:https://www.jb51.cc/windows/363668.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐