C# 如何从Array.ConstrainedCopy获取InvalidCastException

C# 如何从Array.ConstrainedCopy获取InvalidCastException,c#,.net,arrays,C#,.net,Arrays,下面是讨论的示例代码(考虑爬行动物是“动物”,哺乳动物也是“动物”) Animal[]爬行动物=新爬行动物[] {新爬行动物(“蜥蜴”)、新爬行动物(“蛇”)}; 动物[]动物=新动物[] {新爬行动物(“鳄鱼”)、新哺乳动物(“海豚”)}; 尝试 { 数组.ConstrainedCopy(动物,0,爬行动物,0,2); } 捕获(ArrayTypeMismatchException atme) { Console.WriteLine(“[”+String.Join我看到这个方法也会抛出一个In

下面是讨论的示例代码(考虑爬行动物是“动物”,哺乳动物也是“动物”)

Animal[]爬行动物=新爬行动物[]
{新爬行动物(“蜥蜴”)、新爬行动物(“蛇”)};
动物[]动物=新动物[]
{新爬行动物(“鳄鱼”)、新哺乳动物(“海豚”)};
尝试
{
数组.ConstrainedCopy(动物,0,爬行动物,0,2);
}
捕获(ArrayTypeMismatchException atme)
{
Console.WriteLine(“[”+String.Join我看到这个方法也会抛出一个
InvalidCastException
。抛出
InvalidCastException
的条件是:

sourceArray中至少有一个元素不能强制转换为 命中注定


所以我被难住了,如果这种方法声明永远不能对数组元素进行任何强制转换,那么如何从中获得InvalidCastException?

老实说,我认为这只是一个复制粘贴错误;他们只是忘记了将其从异常列表中删除。

下面的代码在Mono 2.10.2.0上抛出了
InvalidCastException
(而问题中的代码不适用)。不过,文档中的解释并不适合这种情况

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) + ']');
}
Animal[]爬行动物=新爬行动物[]
{新爬行动物(“蜥蜴”)、新爬行动物(“蛇”)};
对象[]动物=新对象[]
{新爬行动物(“鳄鱼”)、新哺乳动物(“海豚”)};
尝试
{
数组.ConstrainedCopy(动物,0,爬行动物,0,2);
}
捕获(ArrayTypeMismatchException atme)
{
//Console.WriteLine('['+String.Join(“,”,爬行动物)+']');
}
来自(备注部分):

sourceArray类型必须与destinationArray类型相同或派生自destinationArray类型;否则,将引发ArrayTypeMismatchException

在您的示例中,
动物
数组类型与
爬行动物
数组类型不相同,也不派生自
爬行动物(
动物
不是
爬行动物
)。这就是引发
数组类型不匹配激发的原因


根据上述条件和您示例中的异常消息,可以得出结论,在调用
Array.ConstrainedCopy
方法时,无法获得
InvalidCastException
。这是文档中的一个错误。

我偷偷看了一眼
Array
类,在那里我看到了
Array.containedcpy()
只在内部调用
Array.Copy()
而不进行任何类型验证,其中作为CLR方法Array.Copy()实际上可以抛出
InvalidCastException

(摘自MSDN)

从引用类型或值类型数组复制到对象数组时,将创建一个
对象
来保存每个值或引用,然后进行复制。当从
对象
数组复制到引用类型或值类型数组且无法进行赋值时,将抛出一个
InvalidCastException


我假设
Array.Copy()
只是将
InvalidCastException
提升到
Array.ConstrainedCopy()
,所以从技术上讲,
Array.ConstrainedCopy()
抛出一个
InvalidCastException
,尽管它不应该按照定义抛出。

堆中第一个数组的实际类型是爬虫[]

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") };

如果无法访问
Array.Copy的实际本机实现,我们可能只能检查。以下是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

nedCopy的实现与Array.Copy相同,除了一个
ReliabilityContractAttribute

之外,如果我们在IL反汇编程序中打开ConstrainedCopy,我们会看到它所做的一切就是将其参数加载到堆栈中,并将其传递给Array.Copy。
正如异常状态所述,
Array.ConstrainedCopy
在某些情况下抛出异常,而Array.Copy不抛出异常。
ConstrainedCopy
在复制数组之前验证数组。



示例:regular 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);
    }
}
顺便说一句:
Array.ConstrainedCopy不允许进行加宽转换

结论:
Array.ConstrainedCopy方法不允许某些副本。它比Array.Copy更具辨别力。它还引发异常。通常,ConstrainedCopy不是必需的

关于问题的答案:
System.InvalidCastException:是可通过调用Array.Copy引发的异常之一,
由于Array.ConstrainedCopy正在调用Array.Copy,记录Array.ConstrainedCopy抛出系统.InvalidCastException的指定是正确的,但由于验证的优先级,我们将永远不会看到InvalidCastException,但是。

这是一个很好的问题。遗憾的是,该方法最终是在CLR中实现的,看起来不是这样可能会使用类似reflector的东西来回答这个问题。希望了解此方法的人能够看到并回答…我怀疑被调用的基础方法有一个名为
可靠的
的参数,我假设该参数与所做的保证有关。我怀疑基础方法可能抛出
InvalidCastEx异常
,但当
可靠
参数如本例中所示为真时则不例外。
可靠
在使用基本复制命令时为假(因此在
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);
    }
}