0

I have an array of objects (object[]). All the items in this array have the same type (unknown at compile time). I need to convert this array in a typed array, that is, if the items are integers, I want to get an int[].

I've looked into the Array.ConvertAll method, but I need to specify a specific type in the template, meaning that I have to get the element type then call ConvertAll for each case possible.

I've also looked into the keyword dynamic with no more luck (looks like dynamic[] is the same as object[]).

How can I achieve this?

svick
  • 236,525
  • 50
  • 385
  • 514
gregseth
  • 12,952
  • 15
  • 63
  • 96
  • 1
    Why do you want to do that? How are you going to use the resulting array? Does it really have to be a runtime type (`Type` object), or are generics (`T` type parameter) also okay? – svick Nov 07 '12 at 12:33
  • Just interesting - after runtime conversion `object[]` to `int[]`, what you will do at runtime with your collection? At compile time you will not be able to use your items as `int`s – Sergey Berezovskiy Nov 07 '12 at 12:34
  • I'm using a library with a method like `theMethod(object array)` where array must be an array of a given type (an error is returned in case of `object[]`). – gregseth Nov 07 '12 at 12:50

2 Answers2

4

It sounds like you want something like:

dynamic array = Array.CreateInstance(input[0].GetType(), input.Length);
for (int i = 0; i < input.Length; i++)
{
    array[i] = (dynamic) input[i];
}

Here the dynamic just handles the conversion part for you.

Alternatively:

public static Array ConvertArray(object[] input)
{
    dynamic sample = input[0]; // Just used for type inference
    return ConvertArrayImpl(sample, input);
}

private static T[] ConvertArrayImpl<T>(T sample, object[] input)
{
    return input.Cast<T>().ToArray();
}

You could do make the ConvertArrayImpl call with reflection manually of course, instead of using dynamic typing.

Also note that all of these will fail if the input array is empty...

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Your fist version doesn't work, it throws `RuntimeBinderException` with the message "Cannot implicitly convert type 'object' to 'int'.". Changing the loop body to `array[i] = (dynamic)input[i];` fixes that. – svick Nov 07 '12 at 12:43
2

Similar to Jon's solution you can do without dynamic and make use of the Array type:

public Array Convert(Array a) {
  if (a.GetLength(0) == 0){
    return new int[0];
  }
  var type = a.GetValue(0).GetType();
  var result = Array.CreateInstance(type, a.GetLength(0));
  for (int i = 0; i < a.GetLength(0); i++) {
    result.SetValue(a.GetValue(i), i);
  }
  return result;
}
Sebastian
  • 7,729
  • 2
  • 37
  • 69
  • 2
    Nice - this is a better solution than mine, although I'd probably use `object[]` as the input, so you can just use `0` and `a.Length` instead of all the lower/upper bounds. – Jon Skeet Nov 07 '12 at 13:03
  • @JonSkeet Thanks - I was not aware that actually today you cannot create arrays with a lower bounds other than 0 anymore - they changed that in VB 2003 obviously. I'll update the snippet. – Sebastian Nov 07 '12 at 13:26