How to convert object[] to a more specifically typed array

10,065

Solution 1

It's not really a cast as such (I'm allocating a new array and copying the original), but maybe this can help you out?

Type myType = typeof(string);
object[] myArray = new object[] { "foo", "bar" };

Array destinationArray = Array.CreateInstance(myType, myArray.Length);
Array.Copy(myArray, destinationArray, myArray.Length);

In this code, destinationArray will be an instance of string[] (or an array of whatever type myType was).

Solution 2

You can't perform such a cast, because the arrays object[] and string[] are actually different types and are not convertible. However, if you wanted to pass different such types to a function, just make the parameter IEnumerable. You can then pass an array of any type, list of any type, etc.

    // Make an array from any IEnumerable (array, list, etc.)
    Array MakeArray(IEnumerable parm, Type t)
    {
        if (parm == null)
            return Array.CreateInstance(t, 0);
        int arrCount;
        if (parm is IList)     // Most arrays etc. implement IList
            arrCount = ((IList)parm).Count;
        else
        {
            arrCount = 0;
            foreach (object nextMember in parm)
            {
                if (nextMember.GetType() == t)
                    ++arrCount;
            }
        }
        Array retval = Array.CreateInstance(t, arrCount);
        int ix = 0;
        foreach (object nextMember in parm)
        {
            if (nextMember.GetType() == t)
                retval.SetValue(nextMember, ix);
            ++ix;
        }
        return retval;
    }

Solution 3

This is not a one liner but it can be done with two lines. Given your specified Array of elements of the correct type myArray and the specified Type parameter myType, dynamically calling .Cast<"myType">.ToArray() would work.

var typeConvertedEnumerable = typeof(System.Linq.Enumerable)
    .GetMethod("Cast", BindingFlags.Static | BindingFlags.Public)
    .MakeGenericMethod(new Type[] { myType })
    .Invoke(null, new object[] { myArray });
var typeConvertedArray = typeof(System.Linq.Enumerable)
    .GetMethod("ToArray", BindingFlags.Static | BindingFlags.Public)
    .MakeGenericMethod(new Type[] { myType })
    .Invoke(null, new object[] { typeConvertedEnumerable });

While the method generation is slower than a direct call, it is O(1) on the size of the array. The benefit of this approach is, if IEnumerable<"myType"> would be acceptable, the second line is not needed, and therefore I do not believe the array will be copied.

Solution 4

You'd have to manually go through every object, get the most generic common type between them, and then create a new array of that type and copy the elements. There's no one-liner for this.

Solution 5

This will create the array that you want, but I don't know what you're going to do with it afterwards, since the compiler still doesn't know what the type of the array object is.

Type myType = typeof(string);
object[] myArray = new object[] { "foo", "bar" };

Array myArrayOfTheCorrectType = Array.CreateInstance(myType, myArray.Length);
for (int index = 0; index < myArray.Length; index++)
    myArrayOfTheCorrectType.SetValue(myArray[index], index);
Share:
10,065

Related videos on Youtube

B Bulfin
Author by

B Bulfin

I like bikes. For more information, see here.

Updated on June 01, 2022

Comments

  • B Bulfin
    B Bulfin almost 2 years

    This would be pretty straight forward if I knew the types at compile time or if it was a generic parameter, because I could do something like myArray.Cast<T>() But what I actually have is essentially this. I do not have a known type or generic parameter. I have a System.Type variable.

    // could actually be anything else
    Type myType = typeof(string);  
    
    // i already know all the elements are the correct types
    object[] myArray = new object[] { "foo", "bar" }; 
    

    Is there some kind of reflection magic I can do to get a string[] reference containing the same data? (where string isn't known at compile time)

  • B Bulfin
    B Bulfin almost 13 years
    The actual object references are already correct. It's just that they're contained in an object[]. I just need to copy the same references to a new array.
  • B Bulfin
    B Bulfin almost 13 years
    IEnumerable will not work for me, because I need to assign the array reference to a property via reflection.
  • user541686
    user541686 almost 13 years
    @recursive: If by "correct" you mean that they're the same, then just get the type of the first object and treat it as the most common type. Then create a new array of that type and copy over the objects.
  • Ed Bayiates
    Ed Bayiates almost 13 years
    You could use the same MyFunc above to return a string array too -- from any kind of object (if it isn't string, call ToString on it).
  • Ed Bayiates
    Ed Bayiates almost 13 years
    OK, I changed my function to crawl any IEnumerable to make a string array from it.
  • B Bulfin
    B Bulfin almost 13 years
    Sorry if I wasn't clear. string was just an example I used to illustrate the problem. I need code that will work for any type. My code may or may not actually be handling strings. I don't know that during compile time.
  • Ed Bayiates
    Ed Bayiates almost 13 years
    OK, give me a couple of minutes, I'll make it more generic.
  • Ed Bayiates
    Ed Bayiates almost 13 years
    I've now made it so it creates the array from a given type for any IEnumerable (array, list, whatever).
  • B Bulfin
    B Bulfin almost 13 years
    I know I was asking for a cast in the original question, but this is basically exactly what I actually wanted. Array.CreatInstance() was the part I was missing.