Как преобразовать объект [] в более специфичный типизированный массив - PullRequest
15 голосов
/ 24 июня 2011

Это было бы довольно просто, если бы я знал типы во время компиляции или если бы это был универсальный параметр, потому что я мог бы сделать что-то вроде 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 не известно во время компиляции)

Ответы [ 6 ]

26 голосов
/ 24 июня 2011

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

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 голосов
/ 02 августа 2018

Это не один вкладыш, но это можно сделать двумя строками. Учитывая заданные вами Array элементы правильного типа myArray и указанный Type параметр myType, динамический вызов .Cast<"myType">.ToArray() будет работать.

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

Хотя генерация метода медленнее, чем прямой вызов, она равна O (1) от размера массива. Преимущество этого подхода состоит в том, что если IEnumerable<"myType"> будет приемлемым, вторая строка не нужна, и поэтому я не верю, что массив будет скопирован.

2 голосов
/ 24 июня 2011

Вы не можете выполнить такое приведение, потому что объект массива [] и строка [] на самом деле являются разными типами и не могут быть преобразованы.Однако, если вы хотите передать в функцию различные такие типы, просто сделайте параметр 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;
    }
1 голос
/ 24 июня 2011

Я бы сказал, что ответ не может быть брошен. Я знаю, что многие другие люди предлагали решения, но ответ - нет. Я думаю, что причина в том, что тип массива является объектом, который ниже, чем строка. Компилятор не допустит преобразования вверх, если вы не сделаете это вручную. Я также играл с 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;
    }
}
1 голос
/ 24 июня 2011

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

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);
1 голос
/ 24 июня 2011

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...