Pregunta

Estoy intentando deserializar una matriz de un tipo desconocido en tiempo de compilación. En el tiempo de ejecución, he descubierto el tipo, pero no sé cómo crear una instancia.

Algo como:

Object o = Activator.CreateInstance(type);

que no funciona porque no hay un constructor sin parámetros, Array no parece tener ningún constructor.

¿Fue útil?

Solución

Otros consejos

Puede usar una de las sobrecargas CreateInstance de Array, por ejemplo: -

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

Una publicación bastante antigua, pero al responder a una nueva pregunta, a pesar de publicar un ejemplo relacionado de cómo crear una matriz multidimensional.

Suponiendo que el tipo ( elementType ) como int y una matriz bidimensional, por ejemplo.

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

Cuando es bidimensional, por ejemplo, se puede rellenar como

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

Una alternativa es usar árboles de expresiones para el rendimiento. Por ejemplo si tiene una matriz de tipo , tipo que podría hacer

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();

Esto solo devuelve una matriz vacía. Probablemente no sea muy útil. Los estados de MSDN GetConstructors no garantizan ningún orden, por lo que es posible que necesite una lógica para encontrar el constructor correcto con los parámetros correctos para crear una instancia con el tamaño correcto. Por ejemplo usted podría hacer:

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();
}

Lo mismo puede lograrse mucho más fácilmente con Expression.NewArrayBounds en lugar de Expression.New , más sobre todo funciona si todo lo que tienes es un tipo de elemento de matriz, no un tipo de matriz sí mismo. Demostración:

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

Simplemente cambie type.GetElementType () a simplemente type si lo que está pasando es el propio tipo de elemento.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top