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似乎没有任何构造函数。
4 个解决方案
#2
You can use one of Array's CreateInstance overloads e.g.:-
您可以使用Array的CreateInstance重载之一,例如:-
object o = Array.CreateInstance(type, 10);
#3
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.
假设类型(elementType)为int,例如二维数组。
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 ] ]
#4
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 constructorvar 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:
这只返回一个空数组。可能不是很有用。 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.NewArrayBounds
instead 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 10x = 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.
只需更改type.GetElementType()即可输入您传递的内容是元素类型本身。
#1
Use Array.CreateInstance.
#2
You can use one of Array's CreateInstance overloads e.g.:-
您可以使用Array的CreateInstance重载之一,例如:-
object o = Array.CreateInstance(type, 10);
#3
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.
假设类型(elementType)为int,例如二维数组。
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 ] ]
#4
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 constructorvar 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:
这只返回一个空数组。可能不是很有用。 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.NewArrayBounds
instead 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 10x = 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.
只需更改type.GetElementType()即可输入您传递的内容是元素类型本身。