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

问题描述:

为什么下一个示例抛出System.ArrayTypeMismatchException?为什么IEnumerable的ToArray()扩展方法抛出ArrayTypeMismatchException?

New Int16(){4,5,6}.Cast(of UInt16).ToArray() 

我预计这一线返回一个包含预先4,5和6

感谢UINT16阵列。

这是CastToArray一个bug,IMO。在这个答案中的代码是在C#中,但希望你可以看到它是关于:)

我相信Cast首先试图看看是否一个简单的参考转换将工作 - 即它可以返回相同的参考返回。

例如:

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

不幸的是,它这样做使用CLR规则兼容性 - 在其下UInt16[]Int16[]兼容。导致这种情况的发生:

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

不幸的是,如果你再尝试拨打ToArray(),它不是高兴:

// Explicit type argument just for clarity 
cast.ToArray<ushort>(); // Bang 

ToArray无疑会尝试做一些优化 - 这无法在这种特殊情况下,因为类型并不是它真正期望的那样。

我相信正确行为应该是为Cast返回一个懒惰的迭代器,但为此以后执行失败。例如,如果您尝试从Int16Int32,就会发生这种情况。

现在,回到真的想要做的事情:改用Select来代替。 Cast仅用于拆箱操作和参考类型转换。

+0

谢谢,不幸的是我还没有关于LINQ的知识,你知道,我总是有更多的事情要做。无论如何,再次感谢。 – 2009-12-14 13:47:07

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

New Int16() {4, 5, 6}.Select(Function(x) CType(x, UInt16)).ToArray() 
+0

这就是为什么我打电话演员是不是?如果他们在哪里相同的类型不需要Cast。 – 2009-12-14 12:23:24

+0

'Cast'只在类型兼容时才起作用(一个来自另一个)。 'Int16'和'UInt16'没有什么共同之处。 – 2009-12-14 12:26:25

+0

好吧,有没有办法用CType而不是DirectCast做同样的事情? – 2009-12-14 12:29:23