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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/400900/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 02:02:48  来源:igfitidea点击:

How can I create an instance of an arbitrary Array type at runtime?

c#reflectioncompact-framework.net-2.0

提问by CrashCodes

I'm trying to deserialize an array of an type unknown at compile time. At runtime I've discovered the type, but I don't know how to create an instance.

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

Something like:

就像是:

Object o = Activator.CreateInstance(type);

which doesn't work because there is no parameterless constructor, Array doesn't seem to have any constructor.

这不起作用,因为没有无参数构造函数,Array 似乎没有任何构造函数。

采纳答案by Jon Skeet

回答by AnthonyWJones

You can use one of Array's CreateInstance overloads e.g.:-

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

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

回答by Arghya C

Quite an old post, but while answering a new question, though of posting a related example of creating a multi-dimensional array.

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

Assuming the type (elementType) as intand a two-dimensional array for example.

例如,假设类型 ( elementType) asint和一个二维数组。

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

When it's two dimensional, for example, it can be populated as

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

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 ] ]

回答by nawfal

An alternative is to use expression trees for performance. For e.g. if you have array type, typeyou could do

另一种方法是使用表达式树来提高性能。例如,如果你有数组类型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();

This just returns an empty array. Probably not very useful. MSDN states GetConstructorsdoesn't guarantee any order, so you might need a logic to find right constructor with right parameters to instantiate with correct size. For e.g. you could do:

这只是返回一个空数组。可能不是很有用。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();
}

The same can be achieved much easier with Expression.NewArrayBoundsinstead of Expression.New, more over it works if all you got is array element type, not array type itself. Demo:

使用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][]

Just change type.GetElementType()to simply typeif what you're passing is element type itself.

如果您传递的是元素类型本身,只需更改type.GetElementType()为简单的type