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

发布于 2024-07-10 05:04:38 字数 184 浏览 5 评论 0原文

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

像这样的东西:

Object o = Activator.CreateInstance(type);

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

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

年华零落成诗 2024-07-17 05:04:38

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

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

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

object o = Array.CreateInstance(type, 10);
在风中等你 2024-07-17 05:04:38

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

假设类型 (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 ] ]

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 int and a two-dimensional array for example.

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 ] ]
一梦等七年七年为一梦 2024-07-17 05:04:38

另一种方法是使用表达式树来提高性能。 例如,如果您有数组typetype,您可以这样做

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 即可。

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

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 GetConstructors doesn'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:

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.NewArrayBounds instead of Expression.New, more over it works if all you got is array element type, not array type itself. Demo:

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 type if what you're passing is element type itself.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文