2

I'm working on a serializer and have run into a real wall with multi-dimensional arrays. If I use Activator.CreateInstance() it creates a one dimensional array just fine, but it fails to work when used as follows:

var indices = new[] { 2, 2 };
Type type = typeof(int[,]);
var result = Activator.CreateInstance(type, indices) as Array;

If I instead use Array.CreateInstance() to generate my array, it works for single and multi-dimensional arrays alike. However, all my calls to the SetValue() method on the array, which I use to dynamically set values, generates an exception, whereas it works fine on the single dimensional arrays I created using Activator.CreateInstance(). I'm really struggling to find a viable solution that allows me to dynamically create an array of any dimension/size and then populate the array with values. I'm hoping someone with more reflection experience can shed some light on this.

When trying to create a multi-dimensional array with Activator I get the exception:

Constructor on type 'System.Int32[,]' not found.

When I instead use Array.CreateInstance() and then call SetValue() I get the following exception from the SetValue() call:

Object cannot be stored in an array of this type.

Which frankly makes no sense to me since the value is an int and the array is an int[,].

I am using the 4.5 framework for my project though I recreated the problem with 4.6 as well.

Arghya C
  • 9,805
  • 2
  • 47
  • 66
WiredWiz
  • 646
  • 8
  • 18
  • 1
    I suspect that `Array.CreateInstance(type, indices)` is giving you that error because it doesn't have the type you expect. Calling that actually gives you an `int[,][,]`, not an `int[,]`. – Bobson Dec 28 '15 at 05:38
  • On further thought, this might be [an X-Y problem](http://meta.stackexchange.com/a/233676/165591). Can you add an example of what your incoming data is like, and how you actually want it as an object? If your incoming data is more like a [jagged array than a rectangular matrix](http://stackoverflow.com/q/4648914/298754), then you'll probably need a very different answer, for example. – Bobson Dec 28 '15 at 05:46
  • In this particular instance I'm writing a serializer that needs to serialize/deserialize user data of any type (including multi-dimensional arrays). The issue was in deserializing the serialized data. You were indeed correct. After staring at it so long I had a bit of tunnel vision and kept thinking it was [,] but after you pointed that out I realized it was indeed handing back an array of array instead. – WiredWiz Dec 28 '15 at 06:37

1 Answers1

3

You can call Array.CreateInstance with the actual ElementType which is int in this case.

var indices = new[] { 2, 3 };                
var arr = Array.CreateInstance(typeof(int), indices);

Then you can populate the array with SetValue without any exception. For example

var value = 1;
for (int i = 0; i < indices[0]; i++)
{
    for (int j = 0; j < indices[1]; j++)
    {
        arr.SetValue(value++, new[] { i, j });
    }
}

//arr = [ [ 1, 2, 3 ], [ 4, 5, 6 ] ]
Arghya C
  • 9,805
  • 2
  • 47
  • 66
  • 2
    This doesn't seem generalizable to "an array of any dimension/size", because of the need for a `for` loop per index. – Bobson Dec 28 '15 at 05:36
  • 2
    @Bobson it isn't. It just shows how to create a multidimensional array as that was OP's problem. For the setValue part, I just showed that it doesn't throw exception when written properly. Edited for clarity. – Arghya C Dec 28 '15 at 05:43
  • 1
    Ah, that makes sense, I kept thinking of both CreateInstance methods being the same and not thinking that Array.CreateInstance would obviously want the array element type and not the array type. Thank you to both of you, that indeed fixed the issue. – WiredWiz Dec 28 '15 at 06:35