P.Brian.Mackey
P.Brian.Mackey

Reputation: 44285

Why do we get ArrayTypeMismatch with ref params?

Given the scenerio:

public class Program
{
    static void Main()
    {
        object[] covarientArray= new A[] { new A() };
        object polymorphism = new A();
        object test = covarientArray[0];
        M(ref polymorphism);//fine up to here

        M(ref covarientArray[0]);//ArrayTypeMismatchException
    }

    static void M(ref object o) { Console.WriteLine(o); }
}
class A {}

And the definition of ArrayTypeMisMatch:

The exception that is thrown when an attempt is made to store an element of the wrong type within an array.

This Exception is thrown when an attemp is made to store an element of the wrong type within an array. E.G.:

A[] invalid = new A[1];
invalid[0] = "";//I can't store a type of string within an array of type of A

How does this exception occur? Why is it that we are doing a store operation when Invoking a method with a ref param?

Upvotes: 3

Views: 78

Answers (2)

Chris Sinclair
Chris Sinclair

Reputation: 23218

Why is it that we are doing a store operation when Invoking a method with a ref param?

Providing an array element as the argument to a ref parameter actually is a store operation, at least potentially. (Yeah, you might not reassign it, but the compiler/runtime doesn't necessarily know that)

Imagine if your M method implementation was this:

static void M(ref object o) 
{ 
    o = new B();
}

If we type your covariant array as object[] to so it compiles and works:

object[] covariantArray= new object[] { new A() };
M(ref covariantArray[0]);
Console.WriteLine(covariantArray[0].GetType().Name); //B

It runs and replaced the first element with a new instance of B. Of course, this is perfectly valid for an object[] array. So now if we simply change it to A[]:

object[] covariantArray= new A[] { new A() };
M(ref covariantArray[0]); //ArrayTypeMismatchException
Console.WriteLine(covariantArray[0].GetType().Name);

It throws the exception before the potentially dangerous/catastrophic/dogs-are-cats/up-is-down call to M is processed.

Of course, remove the ref calls or ref against a local variable instead of the array element and it works perfectly fine since you're not messing around with the array contents.

@hvd's answer is probably more correct in that it explains the underlying runtime mechanism for throwing, but at least here's a practical demonstration why it is so.

Upvotes: 1

user743382
user743382

Reputation:

The exception is also thrown when creating a ref to an array element of the wrong type. This is admittedly unclear by just reading the exception text, but it is very briefly mentioned indirectly on the page you linked to:

The following Microsoft intermediate language (MSIL) instructions throw ArrayTypeMismatchException :

ldelema

ldelema (load element address) is the instruction used to create a reference to an array element.

As for the why, it prevents every assignment to every ref argument from needing to do a run-time check of the type.

Upvotes: 3

Related Questions