53

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.

Mark Lakata
  • 19,989
  • 5
  • 106
  • 123

2 Answers2

73

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
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • That doesn't answer why it doesn't work with //attempt1 though, which I'm rather curious about myself (given that //attempt2 works). – zebediah49 Aug 05 '10 at 21:51
  • 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 Aug 07 '10 at 04:23
  • `Array.CreateInstance` returns an object of type `Array` and not e.g. `int[]`. Given a type variable `Type t = typeof(int);` is there anyway to create an object of type `int[]`? – NetMage Jan 09 '19 at 21:42
  • @NetMage: It does create an `int[]`, you just need to cast: `int[] x = (int[]) Array.CreateInstance(typeof(int), 10);` – Jon Skeet Jan 09 '19 at 23:32
  • 1
    I can't cast, I only have `t` at runtime. Background: I am trying to dynamically create a valuetype for use in a `Func` /`Action` pair as a variable I can read and assign. I am attempting to cheat by creating e.g. `a = new int[1]()` and read/writing `a[0]`. I was trying to avoid adding `Expression.Convert` to cast `Array` to `int[]` in my `Func`/`Action` pair. Perhaps I'll add some separate questions. – NetMage Jan 09 '19 at 23:41
  • Added [my question](https://stackoverflow.com/q/54120167/2557128). – NetMage Jan 09 '19 at 23:56
52

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
  • 114,645
  • 34
  • 221
  • 317
  • 3
    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 Aug 07 '10 at 04:20
  • Just used this and the chunk from http://stackoverflow.com/a/20052747/561690 to enable a Deep Copy implementation that handles arrays - probably not the best way to do it, but it's working for me! Thanks! – Code Jockey Jul 31 '14 at 15:51
  • 1
    Simpler: Activator.CreateInstance(t, 1) – net_prog Jul 07 '15 at 10:17
  • Can anyone provide me an example of create instance for array without mentioning arraylength – Meena Sep 16 '19 at 10:48