Pragmateek
Pragmateek

Reputation: 13374

Direct dynamic conversion to array of different type

I must be missing something obvious but I don't find a direct way of converting an array of type Object[] to an array of type TE[] with TE only known at runtime.

Here is a working version of what I'm trying to achieve:

using System;
using System.Globalization;
using System.Linq;

namespace TestArrays
{
    class Program
    {
        static T Parse<T>(string s)
        {
            T result;

            if (typeof(T).IsArray)
            {
                var TE = typeof(T).GetElementType();
                var rawResult = s.Split(',').Select(x => Convert.ChangeType(x, TE, CultureInfo.InvariantCulture)).ToArray();
                result = (T)(object)Array.CreateInstance(TE, rawResult.Length);
                Array.Copy(rawResult, (Array)(object)result, rawResult.Length);
            }
            else
            {
                result = (T)Convert.ChangeType(s, typeof(T), CultureInfo.InvariantCulture);
            }

            return result;
        }

        static void Main(string[] args)
        {
            Console.WriteLine(Parse<object>("abc"));
            Console.WriteLine(Parse<string>("abc"));
            Console.WriteLine(Parse<int>("123456"));
            Console.WriteLine(Parse<double>("123.456"));

            Console.WriteLine(Parse<object[]>("a,b,c"));
            Console.WriteLine(Parse<string[]>("a,b,c"));
            Console.WriteLine(Parse<int[]>("123,456,789"));
            Console.WriteLine(Parse<double[]>("123.456,456.789,789.101112"));
        }
    }
}

I want to convert rawResult which is of type Object[] to TE[] which is the expected return type.

I understand that a direct conversion is not always possible as the size of the array elements may vary.
But here I'd like to convert to another reference type so it could be possible to be done in-place without having to create a new array and allocate the same quantity of memory.

Moreover the elements can be kept as they are already references of the target TE type.

I've seen Array.ConvertAll but it would too returns an Object[].

Upvotes: 0

Views: 788

Answers (1)

Basil Kosovan
Basil Kosovan

Reputation: 1069

At least we can create a new method for array:

static T[] ParseArray<T>(string s)
{
    var result = s.Split(',').Select(x => (T)Convert.ChangeType(x, typeof(T), CultureInfo.InvariantCulture)).ToArray();
    return result;
}

And call this method from Parse<t>():

static T Parse<T>(string s)
{
    T result;
    if (typeof(T).IsArray)
    {
        var TE = typeof(T).GetElementType();

        MethodInfo method = typeof(Program).GetMethod("ParseArray", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);
        MethodInfo generic = method.MakeGenericMethod(TE);
        result = (T)generic.Invoke(null, new object[] { s });
    }
    else
    {
        result = (T)Convert.ChangeType(s, typeof(T), CultureInfo.InvariantCulture);
    }

    return result;
}

Upvotes: 2

Related Questions