Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get InvalidCastException from Array.ConstrainedCopy

Tags:

arrays

c#

.net

Here is the sample code for the discussion (consider Reptile "is a" Animal and Mammal "is a" Animal too)

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) + ']');
}

When I run this code I get a ArrayTypeMismatchException, with as comment

Array.ConstrainedCopy will only work on array types that are provably compatible, without any form of boxing, unboxing, widening, or casting of each array element. Change the array types (i.e., copy a Derived[] to a Base[]), or use a mitigation strategy in the CER for Array.Copy's less powerful reliability contract, such as cloning the array or throwing away the potentially corrupt destination array.

However when I look at MSDN I see this method also throws an InvalidCastException. The condition for throwing an InvalidCastException is:

At least one element in sourceArray cannot be cast to the type of destinationArray.

So I am stumped, how do you get an InvalidCastException out of this method, if as it states there can never be any casting of an array element?

like image 513
Mishax Avatar asked Sep 18 '13 06:09

Mishax


2 Answers

Without access to the actual native implementation of Array.Copy, the best we can probably do is examine the Shared Source CLI. Here are the relevant lines of code from 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]
}

When Array.ConstrainedCopy calls SystemNative::ArrayCopy with the reliable parameter set to TRUE, either the array is copied using memmove or ArrayTypeMismatchException is thrown. In neither case will InvalidCastException be thrown.

like image 100
Michael Liu Avatar answered Sep 29 '22 23:09

Michael Liu


Honestly, I think it's just a copy-paste typo; they just forgot to remove it from the list of exceptions.

like image 39
user541686 Avatar answered Sep 29 '22 22:09

user541686