Как преобразовать объект [] в более типизированный массив

Это было бы довольно просто, если бы я знал типы во время компиляции или если это был общий параметр, потому что я мог бы сделать что-то вроде myArray.Cast<T>() Но то, что у меня на самом деле, по существу это. У меня нет известного типа или общего параметра. У меня есть переменная System.Type.

// 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" }; 

Есть ли какая-то магия отражения, которую я могу сделать, чтобы получить ссылку string[], содержащую те же данные? (где string не известно во время компиляции)

Ответ 1

На самом деле это не актерский состав (я выделяю новый массив и копирую оригинал), но, может быть, это может помочь вам?

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

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

В этом коде destinationArray будет экземпляр string[] (или массив любого типа myType).

Ответ 2

Вы не можете выполнить такой отбор, потому что объект массивов [] и строка [] на самом деле являются разными типами и не являются конвертируемыми. Однако, если вы хотите передать разные типы в функцию, просто введите параметр IEnumerable. Затем вы можете передать массив любого типа, список любого типа и т.д.

    // 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;
    }

Ответ 3

Вам придется вручную пройти через каждый объект, получить общий общий тип между ними, а затем создать новый массив этого типа и скопировать элементы. Для этого нет ни одного лайнера.

Ответ 4

Это создаст массив, который вы хотите, но я не знаю, что вы собираетесь с ним делать после этого, поскольку компилятор все еще не знает, что такое тип объекта массива.

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);

Ответ 5

Я бы сказал, что ответ не может быть брошен. Я знаю, что многие люди предлагали решения, но ответ - нет. Я думаю, причина в том, что тип массива - это объект, который меньше, чем строка. Компилятор не допустит, чтобы upconversion произошла, если вы не сделаете это вручную. Я также играл с материалом DLR, но он все еще набирает его как объект.

class Program
{
    static void Main(string[] args)
    {
        // could actually be anything else
        Type myType = typeof(string);
        Type myArrayType = Array.CreateInstance(myType, 1).GetType();

        // i already know all the elements are the correct types
        object[] myArray = new object[] { "foo", "bar" };

        MethodInfo castMethod = typeof(Program).GetMethod("Cast").MakeGenericMethod(myArrayType);
        object castedObject = castMethod.Invoke(null, new object[] { myArray });
    }

    public static T Cast<T>(object o)
    {
        return (T)o;
    }
}