为什么IEnumerable的ToArray()扩展方法抛出ArrayTypeMismatchException?

Ign*_*cia 5 .net vb.net ienumerable exception

为什么下一个示例抛出System.ArrayTypeMismatchException?

New Int16(){4,5,6}.Cast(of UInt16).ToArray()
Run Code Online (Sandbox Code Playgroud)

我希望这一行返回一个包含4,5和6的UInt16数组.

提前致谢.

Jon*_*eet 7

这是一个bug Cast或者ToArray,IMO.这个答案中的代码是在C#中,但希望你能看到它的内容:)

我相信Cast首先会尝试查看简单的引用转换是否有效 - 即它可以返回相同的引用.

例如:

String x = "hello";
IEnumerable<char> y = x.Cast<char>();
Console.WriteLine(object.ReferenceEquals(x, y)); // Prints true
Run Code Online (Sandbox Code Playgroud)

不幸的是,这是否使用CLR规则的兼容性-根据该UInt16[]Int16[] 兼容的.这导致了这种情况发生:

short[] array = new short[]{4, 5, 6};
IEnumerable<ushort> cast = array.Cast<ushort>();
Console.WriteLine(object.ReferenceEquals(array, cast)); // Prints True
Run Code Online (Sandbox Code Playgroud)

不幸的是,如果你试着打电话ToArray(),那就不开心了:

// Explicit type argument just for clarity
cast.ToArray<ushort>(); // Bang
Run Code Online (Sandbox Code Playgroud)

ToArray 毫无疑问会尝试进行一些优化 - 在这种特殊情况下失败,因为类型不是它真正期望的那种.

我相信正确的行为应该是Cast返回一个惰性迭代器,但是当它稍后执行时会失败.那是,如果你试图从去会发生什么Int16Int32,例如.

现在,回到你真正想做的事情:改用Select呼叫.Cast仅用于拆箱操作和引用类型转换.


Dar*_*rov 5

因为Int16UInt16是不同的类型.你可以试试这个:

New Int16() {4, 5, 6}.Select(Function(x) CType(x, UInt16)).ToArray()
Run Code Online (Sandbox Code Playgroud)