如何在运行时创建任意Array类型的实例?

时间:2008-12-30 17:20:35

标签: c# reflection compact-framework .net-2.0

我正在尝试在编译时反序列化未知类型的数组。在运行时我发现了类型,但我不知道如何创建实例。

类似的东西:

Object o = Activator.CreateInstance(type);

由于没有无参数构造函数而无效,因此Array似乎没有任何构造函数。

4 个答案:

答案 0 :(得分:53)

答案 1 :(得分:12)

您可以使用Array的CreateInstance重载之一,例如: -

object o = Array.CreateInstance(type, 10);

答案 2 :(得分:3)

相当古老的帖子,但在回答一个新问题时,虽然发布了创建多维数组的相关示例。

假设类型(elementType)为int和二维数组。

var size = new[] { 2, 3 };                
var arr = Array.CreateInstance(typeof(int), size);

例如,当它是二维时,它可以填充为

var value = 1;
for (int i = 0; i < size[0]; i++)
    for (int j = 0; j < size[1]; j++)
        arr.SetValue(value++, new[] { i, j });
//arr = [ [ 1, 2, 3 ], [ 4, 5, 6 ] ]

答案 3 :(得分:3)

另一种方法是使用表达式树来提高性能。对于例如如果你有数组类型type你可以做

var ctor = type.GetConstructors().First(); // or find suitable constructor
var argsExpr = ctor.GetParameters().Select(x => Expression.Constant(0)); 
var func = Expression.Lambda<Func<object>>(Expression.New(ctor, argsExpr)).Compile();

这只返回一个空数组。可能不是很有用。 MSDN状态GetConstructors并不保证任何顺序,因此您可能需要一个逻辑来找到具有正确参数的正确构造函数,以便以正确的大小进行实例化。对于例如你可以这样做:

static Func<object> ArrayCreateInstance(Type type, params int[] bounds) // can be generic too
{
    var ctor = type
        .GetConstructors()
        .OrderBy(x => x.GetParameters().Length) // find constructor with least parameters
        .First();

    var argsExpr = bounds.Select(x => Expression.Constant(x)); // set size
    return Expression.Lambda<Func<object>>(Expression.New(ctor, argsExpr)).Compile();
}

使用Expression.NewArrayBounds而不是Expression.New可以更容易地实现相同的功能,如果您只获得了数组元素类型而不是数组类型本身,则可以使用更多功能。演示:

static Func<object> ArrayCreateInstance(Type type, params int[] bounds) // can be generic too
{
    var argsExpr = bounds.Select(x => Expression.Constant(x)); // set size
    var newExpr = Expression.NewArrayBounds(type.GetElementType(), argsExpr);
    return Expression.Lambda<Func<object>>(newExpr).Compile();
}

// this exercise is pointless if you dont save the compiled delegate, but for demo purpose:

x = string[] {...
y = ArrayCreateInstance(x.GetType(), 10)(); // you get 1-d array with size 10

x = string[,,] {...
y = ArrayCreateInstance(x.GetType(), 10, 2, 3)(); // you get 3-d array like string[10, 2, 3]

x = string[][] {...
y = ArrayCreateInstance(x.GetType(), 10)(); // you get jagged array like string[10][]

如果您传递的内容属于元素类型,只需将type.GetElementType()更改为type