从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. 编辑:(以猫为例) 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 另一个问题是为什么它是这样实现的? (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- 该项目的目标是“.NET Framework 4.5”,Windows
- ms windows network活动字节在命令行中发送和接收
- Microsoft Windows中的FIPS“单用户模式”要求
- .net – Windows WPF或Silverlight中的VT100终端
- Windows CE上的C#.NET 3.5 CF,更改DataGrid中的行
- .net – 通过SetSecurityDescriptor设置WMI ACL
- Azure功能 – 无法加载文件或程序集”Microsoft.
- 当密码包含“@”符号时,在Windows上使用Git无法正
- windows – 如何强制Perl脚本使用ActiveState的w
- 如何给Windows2016新建IIS并建立网站