Как получить InvalidCastException из Array.ConstrainedCopy
Вот пример кода для обсуждения (см. "Рептилия" - "Животное и млекопитающее" - это "Животное тоже" )
Animal[] reptiles = new Reptile[]
{ new Reptile("lizard"), new Reptile("snake") };
Animal[] animals = new Animal[]
{ new Reptile("alligator"), new Mammal("dolphin") };
try
{
Array.ConstrainedCopy(animals, 0, reptiles, 0, 2);
}
catch (ArrayTypeMismatchException atme)
{
Console.WriteLine('[' + String.Join<Animal>(", ", reptiles) + ']');
}
Когда я запускаю этот код, я получаю исключение ArrayTypeMismatchException, с комментарием
Array.ConstrainedCopy будет работать только с типами массивов, которые предположительно совместимый, без какой-либо формы бокса, распаковки, расширения или литья каждого элемента массива. Измените типы массивов (т.е. Скопируйте Derived [] на базу []) или использовать стратегию смягчения в CER для Array.Copy's менее мощный контракт на надежность, например, клонирование массива или отбрасывая потенциально поврежденный целевой массив.
Однако, когда я смотрю MSDN, я вижу, что этот метод также генерирует InvalidCastException
. Условие throw InvalidCastException
:
По крайней мере один элемент в sourceArray не может быть отнесен к типу destinationArray.
Итак, я в тупике, как вы получаете InvalidCastException из этого метода, если в нем указано, что никогда не может быть никакого литья элемента массива?
Ответы
Ответ 1
Без доступа к фактической встроенной реализации Array.Copy
лучшее, что мы, возможно, можем сделать, это изучить CLI общего доступа. Вот соответствующие строки кода из clr\src\vm\comsystem.cpp:
FCIMPL6(void, SystemNative::ArrayCopy, ArrayBase* m_pSrc, INT32 m_iSrcIndex, ArrayBase* m_pDst, INT32 m_iDstIndex, INT32 m_iLength, CLR_BOOL reliable)
{
// ...
r = CanAssignArrayTypeNoGC(gc.pSrc, gc.pDst);
if (r == AssignWrongType) {
// [Throw ArrayTypeMismatchException]
}
if (r == AssignWillWork) {
// [Copy the array using memmove, which won't throw any exception]
return;
}
else if (reliable) {
// [Throw ArrayTypeMismatchException]
}
// [Handle other cases]
}
Когда Array.ConstrainedCopy
вызывает SystemNative::ArrayCopy
с параметром reliable
, установленным на TRUE
, либо копируется массив с использованием memmove
, либо ArrayTypeMismatchException
. В любом случае не будет выбрано InvalidCastException
.
Ответ 2
Честно говоря, я думаю, что это просто опечатка для копирования-вставки; они просто забыли удалить его из списка исключений.
Ответ 3
Из MSDN (раздел Замечания):
Тип sourceArray должен быть таким же или полученным из типа destinationArray; в противном случае создается исключение ArrayTypeMismatchException.
В вашем примере тип массива animals
не совпадает с производным от типа массива reptiles
(или Animal
не является Reptile
). Вот почему бросается ArrayTypeMismatchExcetion
.
Исходя из приведенных выше условий и сообщения об исключении из вашего примера, можно сделать вывод, что при вызове метода Array.ConstrainedCopy
нет способа получить InvalidCastException
. Это ошибка в документации.
Ответ 4
Фактическим типом первого массива в куче является Reptile [].
Animal[] reptiles = new Reptile[] { ... };
//IL_0002: newarr Reptile
Второй массив:
Animal[] animals = new Animal[] { ... };
// IL_0025: newarr Animal
От Рептилии [] до Животного [] нет никакого эффекта.
Таким образом, это правильное поведение метода Array.ConstrainedCopy().
Этот код будет работать правильно:
Animal[] reptiles = new Animal[] { new Reptile("lizard"), new Reptile("snake") };
Animal[] animals = new Animal[] { new Reptile("alligator"), new Mammal("dolphin") };
Ответ 5
ConstrainedCopy имеет ту же реализацию, что и Array.Copy, за исключением ReliabilityContractAttribute
.
Если мы откроем ConstrainedCopy в IL Disassembler, мы увидим, что все, что он делает, это загрузить свои аргументы в стек и передать их в Array.Copy.
Поскольку состояние исключений, Array.ConstrainedCopy
выдает исключения в некоторых случаях, когда Array.Copy этого не делает.
ConstrainedCopy
проверяет массивы перед их копированием.
![enter image description here]()
Пример. Обычный метод Array.Copy без малейшей копии скопирует массив байтов в массив int. Вместо этого метод Array.ConstrainedCopy создает исключение. Это может повысить надежность.
class Program
{
static void Main()
{
byte[] original = new byte[10];
original[0] = 1;
int[] destination = new int[10];
// This will work if you call Array.Copy instead.
Array.ConstrainedCopy(original, 0, destination, 0, original.Length);
}
}
BTW:
Array.ConstrainedCopy не позволяет выполнять расширенное преобразование.
Вывод:
Метод Array.ConstrainedCopy не позволяет выполнять определенные копии. Это более дискриминационно, чем Array.Copy. Он также генерирует исключения. Часто ConstrainedCopy не требуется.
О вопросе:
System.InvalidCastException: Является одним из исключений, которые могут быть выбраны путем вызова Array.Copy,
поскольку Array.ConstrainedCopy вызывает Array.Copy. Правильно документировать выделение Array.ConstrainedCopy, бросая System.InvalidCastException, но из-за приоритета проверки мы никогда не увидим InvalidCastExceptionbut.
Ответ 6
Следующий код выдает InvalidCastException
в Моно 2.10.2.0 (тогда как код из вопроса не указан). Объяснение из документации не подходит для этого случая.
Animal[] reptiles = new Reptile[]
{ new Reptile("lizard"), new Reptile("snake") };
object[] animals = new object[]
{ new Reptile("alligator"), new Mammal("dolphin") };
try
{
Array.ConstrainedCopy(animals, 0, reptiles, 0, 2);
}
catch (ArrayTypeMismatchException atme)
{
//Console.WriteLine('[' + String.Join<Animal>(", ", reptiles) + ']');
}
Ответ 7
Я заглянул в класс Array
, где увидел, что Array.ContrainedCopy()
просто вызывает Array.Copy()
внутри без какой-либо проверки типов, где, как метод CLR Array.Copy(), действительно может выбросить InvalidCastException
:
(из MSDN Array.Copy
При копировании из массива ссылочного типа или массива значений в массив объектов создается Object
для хранения каждого значения или ссылки и последующего копирования. При копировании из массива Object
в массив ссылочного типа или массива значений и назначение не возможно, создается InvalidCastException
.
Я предполагаю, что Array.Copy()
просто увеличивает значение InvalidCastException
до Array.ConstrainedCopy()
, поэтому технически возможно, что Array.ConstrainedCopy()
выбрасывает InvalidCastException
, хотя это не должно быть в определении.