以下是讨论的示例代码(认为Reptile“是”动物和哺乳动物“是”动物也是如此“
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 [] 到Base []),或在CER的Array.Copy中使用缓解策略 不太强大的可靠性契约,比如克隆数组或者 扔掉潜在腐败的目的地阵列。
但是,当我查看MSDN时,我发现此方法也会引发InvalidCastException
。抛出InvalidCastException
的条件是:
sourceArray中至少有一个元素无法强制转换为类型 destinationArray。
所以我很难过,做你是如何从这个方法中得到一个InvalidCastException的,如果它声明永远不会有任何数组元素的转换?
答案 0 :(得分:7)
如果无法访问Array.Copy
的实际原生实现,我们可以做的最好的事情就是检查Shared Source 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
。
答案 1 :(得分:3)
老实说,我认为这只是一个复制粘贴错字;他们只是忘了把它从例外列表中删除。
答案 2 :(得分:3)
来自MSDN(备注部分):
sourceArray 类型必须与 destinationArray 类型相同或派生自 destinationArray 类型;否则,抛出ArrayTypeMismatchException。
在您的示例中,animals
数组类型与reptiles
数组类型不同或派生自Animal
不是Reptile
)。这就是抛出ArrayTypeMismatchExcetion
的原因。
根据上述条件和您示例中的异常消息,可以得出结论,在调用InvalidCastException
方法时无法获得Array.ConstrainedCopy
。这是文档中的一个错误。
答案 3 :(得分:3)
堆中第一个数组的实际类型是Reptile []。
Animal[] reptiles = new Reptile[] { ... };
//IL_0002: newarr Reptile
第二阵列:
Animal[] animals = new Animal[] { ... };
// IL_0025: newarr Animal
没有从Reptile []到Animal []的演员表。 所以它是Array.ConstrainedCopy()方法的正确行为。
此代码将正常运行:
Animal[] reptiles = new Animal[] { new Reptile("lizard"), new Reptile("snake") };
Animal[] animals = new Animal[] { new Reptile("alligator"), new Mammal("dolphin") };
答案 4 :(得分:3)
ReliabilityContractAttribute
之外, ConstrainedCopy 与Array.Copy具有相同的实现。
如果我们在IL反汇编程序中打开ConstrainedCopy,我们发现它只是将其参数加载到堆栈并将它们传递给Array.Copy。
正如异常所述,Array.ConstrainedCopy
在某些情况下抛出异常,而Array.Copy则不会。
ConstrainedCopy
在复制数据之前验证数组。
示例:常规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,所以记录抛出System.InvalidCastException的Array.ConstrainedCopy的规范是正确的,但是由于验证的优先级,我们永远不会看到InvalidCastException但是。
答案 5 :(得分:2)
以下代码会在 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) + ']');
}
答案 6 :(得分:1)
我偷偷进入Array
类,在那里我看到Array.ContrainedCopy()
只调用Array.Copy()
而没有任何类型验证,因为CLR方法Array.Copy()实际上可以抛出InvalidCastException
:
(来自MSDN Array.Copy
从reference-type或value-type数组复制到Object数组时,会创建
Object
来保存每个值或引用,然后复制。从Object
数组复制到引用类型或值类型数组并且无法进行赋值时,会抛出InvalidCastException
。
我认为Array.Copy()
只会将InvalidCastException
提升为Array.ConstrainedCopy()
,因此技术上可能Array.ConstrainedCopy()
会抛出InvalidCastException
,尽管不应该{0}}根据定义。