views:

57

answers:

2

I can't figure out how to make this work:

object x = new Int32[7];
Type t = x.GetType();

// now forget about x, and just use t from here.

// attempt1 
object y1 = Activator.CreateInstance(t); // fails with exception

// attempt2
object y2 = Array.CreateInstance(t, 7);  // creates an array of type Int32[][] ! wrong

What's the secret sauce? I can make the second one work if I can get the type of the elements of the array, but I haven't figured that one out either.

+5  A: 

You need Type.GetElementType() to get the non-array type:

object x = new Int32[7];
Type t = x.GetType();
object y = Array.CreateInstance(t.GetElementType(), 7);

Alternatively, if you can get the type of the element directly, use that:

Type t = typeof(int);
object y = Array.CreateInstance(t, 7);

Basically, Array.CreateInstance needs the element type of the array to create, not the final array type.

Jon Skeet
That doesn't answer why it doesn't work with //attempt1 though, which I'm rather curious about myself (given that //attempt2 works).
zebediah49
A few seconds after I posted my question, I discovered GetElementType(), and that is how I implemented it.My goal was to make an TreeView derived widget that lets you throw any struct at it (with arbitrary fields, including arrays, primatives and more structs), and display the whole thing and let you edit it and give you a copy of the edited struct.
Mark Lakata
+4  A: 

Just to add to Jon's answer. The reason attempt 1 fails is because there's no default constructor for Int32[]. You need to supply a length. If you use the overload, which takes an array of arguments it will work:

// attempt1 
object y1 = Activator.CreateInstance(t, new object[] { 1 }); // Length 1
Brian Rasmussen
Both of these answers get me out of the pickle, but I think this is the more elegant method. I would not have guessed this answer, but I see how it is necessary to provide an argument to the constructor of an array, because the length of the array is not part of the type.
Mark Lakata