Casting arrays fails at runtime

E

eric.dennison

In the sample below:

testClass is derived from object.

We can cast object to testClass, no problem
We can cast testClass[] to object[] no problem
Compiler is ok with cast object[] to testClass[] but fails at runtime.

Why?

I understand this can be worked around using Array.Copy, but I actually
am trying to do the cast from object[] to testClass[] within
Type.InvokeMember and so can't get my hands on the destination
testClass[] member at compile time. Enough to make me head spin.

Heck, I don't even know how to do the cast within InvokeMember, so I'm
two levels away from a solution. Any ideas out there??

-Eric

Sample code:

public class testClass : object
{
public int testMember;
}

// this works great
public void testMethod1()
{
object[] objArray;
testClass[] testArray = new testClass[1];
objArray = testArray;
}

// this fails on the last line
public void testMethod2()
{
// first, we can cast happily from object to testClass
object objSingle = new object();
testClass testSingle;
testClass testTemp = new testClass();
testTemp.testMember = 55;
objSingle = testTemp;
testSingle = (testClass)objSingle;
// testSingle.testMember does indeed == 55

// on the other hand, if we're dealing in arrays...
object[] objArray = new object[1];
testClass[] testArray;
objArray[0] = new testClass();

// **** compiler is ok with this, but fails at runtime
****
testArray = (testClass[])objArray;
}
 
B

Barry Kelly

In the sample below:

testClass is derived from object.

We can cast object to testClass, no problem
We can cast testClass[] to object[] no problem
Compiler is ok with cast object[] to testClass[] but fails at runtime.

This behaviour of the .NET runtime, where T and S are types and S is a
subtype of T, where S[] can be cast to T[], seems to have been
introduced solely for compatibility with the Java language. It's
important to point out that it involves polymorphism. That is, S[]
stored in a variable of type T[] is *still*, at runtime, of type S[].

This becomes apparent when a third type, U, also derived from T, is
stored at runtime into an S[] which is being referred, polymorphically,
through a value of type T[]. (It causes a runtime exception.)

Basically, every store and load to and from an array of a reference type
is actually a virtual method call which uses dynamic dispatch based on
the runtime type of the array value.

For example:

---8<---
class App
{
static void Main()
{
string[] foo = { "a", "b" };
object[] bar = foo;
bar[0] = new App(); // Throws exception at runtime,
// because the object referred to by bar is not an object[]
// but is in fact a string[], which can't store App instances.

// That's why you can't cast an object[] value to string[],
// even if it only contains strings. It has to be a string[]
// value to begin with, when it was constructed.
}
}
--->8---

Your code tries to cast an object[] to a testClass[], but an object[] is
*not* a testClass[], even if all it contains is values
assignment-compatible with variables of type testClass[].

-- Barry
 
E

eric.dennison

Your code tries to cast an object[] to a testClass[], but an object[] is
*not* a testClass[], even if all it contains is values
assignment-compatible with variables of type testClass[].

Thanks for the insight, Barry.

Looks to me like the way out is through Array.CreateInstance, where I
can generate the correct type of array at runtime (which is
fundamentally what I need to do), then drag the whole thing around as
an object reference. Had to read your answer through several times
before I shifted my thinking in the right direction.

-Eric
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top