【问题标题】:Why this ToArray() extension method of IEnumerable throws ArrayTypeMismatchException?为什么这个 IEnumerable 的 ToArray() 扩展方法会抛出 ArrayTypeMismatchException?
【发布时间】:2010-12-26 09:57:38
【问题描述】:

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

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

我预计这行会返回一个包含 4,5 和 6 的 UInt16 数组。

提前致谢。

【问题讨论】:

    标签: .net vb.net exception ienumerable


    【解决方案1】:

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

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

    【讨论】:

    • 这就是我打电话给 Cast 的原因,不是吗?如果它们的类型相同,则不需要 Cast。
    • Cast 仅在类型兼容时才有效(一个派生自另一个)。 Int16UInt16 没有共同点。
    • 好的,有没有办法用 CType 而不是 DirectCast 做同样的事情?
    • 你可以这样做:New Int16() {4, 5, 6}.Select(Function(x) CType(x, UInt16)).ToArray()
    【解决方案2】:

    这是 CastToArray,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 返回一个惰性迭代器,但是当它稍后执行时它会失败。例如,如果您尝试从 Int16 转到 Int32,就会发生这种情况。

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

    【讨论】:

    • 谢谢,不幸的是我对 LINQ 仍然一无所知,而且我总是有更紧急的事情要做,你知道的。无论如何,再次感谢。
    猜你喜欢
    • 1970-01-01
    • 2011-01-25
    • 2015-07-22
    • 1970-01-01
    • 1970-01-01
    • 2014-10-24
    • 2019-03-17
    • 2022-01-05
    • 2010-11-09
    相关资源
    最近更新 更多