Почему этот метод расширения ToArray () IEnumerable выбрасывает ArrayTypeMismatchException? - PullRequest
5 голосов
/ 14 декабря 2009

почему в следующем примере выдается исключение System.ArrayTypeMismatchException?

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

Я ожидал, что эта строка вернет массив UInt16, содержащий 4,5 и 6.

Заранее спасибо.

Ответы [ 2 ]

7 голосов
/ 14 декабря 2009

Это ошибка в Cast или ToArray, 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 предназначен только для операций распаковки и преобразования ссылочных типов.

5 голосов
/ 14 декабря 2009

Потому что Int16 и UInt16 - это разные типы. Вы можете попробовать это:

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