如何将object []转换为更具体的类型化数组

时间:2011-06-24 16:03:43

标签: c# arrays reflection casting

如果我在编译时知道类型或者它是一个通用参数,这将是非常简单的,因为我可以做类似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 个答案:

答案 0 :(得分:26)

这不是真正的演员(我正在分配一个新阵列并复制原件),但也许这可以帮到你?

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的任何类型的数组)。

答案 1 :(得分:2)

您无法执行此类强制转换,因为数组object []和string []实际上是不同的类型且不可转换。但是,如果要将不同的此类型传递给函数,只需将参数设置为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;
    }

答案 2 :(得分:2)

这不是一个班轮,但可以用两行完成。给定您指定的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">可以接受,则不需要第二行,因此我不相信该数组将被复制。

答案 3 :(得分:1)

您必须手动浏览每个对象,在它们之间获取最通用的公共类型,然后创建该类型的新数组并复制元素。没有任何一个班轮。

答案 4 :(得分:1)

这将创建你想要的数组,但我不知道你之后会用它做什么,因为编译器仍然不知道数组对象的类型是什么。

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 :(得分:1)

我会说答案是不能演员。我知道很多其他人都提供了解决方案,但答案是肯定的。我认为原因是因为数组的类型是object,它低于string。除非您手动执行,否则编译器不会发生上转换。我也玩过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;
    }
}