Ответ 1
Используйте Array.CreateInstance.
Я пытаюсь десериализовать массив неизвестного типа во время компиляции. Во время выполнения я обнаружил тип, но я не знаю, как создать экземпляр.
Что-то вроде:
Object o = Activator.CreateInstance(type);
который не работает, потому что нет конструктора без параметров, у массива нет конструктора.
Используйте Array.CreateInstance.
Вы можете использовать одну из перегрузок Array CreateInstance, например: -
object o = Array.CreateInstance(type, 10);
Довольно старое сообщение, но при ответе на новый вопрос, хотя и размещать связанный пример создания многомерного массива.
Предполагая тип (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 ] ]
Альтернативой является использование деревьев выражений для производительности. Напр. если у вас есть тип массива, 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
, если то, что вы проходите, это сам тип элемента.