Domanda

Sto cercando di deserializzare un array di un tipo sconosciuto al momento della compilazione. In fase di esecuzione ho scoperto il tipo, ma non so come creare un'istanza.

Qualcosa del tipo:

Object o = Activator.CreateInstance(type);

che non funziona perché non esiste un costruttore senza parametri, Array non sembra avere alcun costruttore.

È stato utile?

Soluzione

Altri suggerimenti

È possibile utilizzare uno dei sovraccarichi CreateInstance di Array, ad esempio :-

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

Abbastanza un vecchio post, ma pur rispondendo a una nuova domanda, sebbene di pubblicare un esempio correlato di creazione di un array multidimensionale.

Supponendo il tipo ( elementType ) come int e, ad esempio, un array bidimensionale.

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

Quando è bidimensionale, ad esempio, può essere popolato come

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

Un'alternativa è usare gli alberi delle espressioni per le prestazioni. Ad es. se hai l'array type , type puoi farlo

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

Questo restituisce solo un array vuoto. Probabilmente non molto utile. MSDN afferma che GetConstructors non garantisce alcun ordine, quindi potresti aver bisogno di una logica per trovare il costruttore giusto con i parametri giusti per creare un'istanza con le dimensioni corrette. Ad es. potresti fare:

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 stesso può essere ottenuto molto più facilmente con Expression.NewArrayBounds invece di Expression.New , più funziona se tutto ciò che ottieni è il tipo di elemento array, non il tipo di array si. 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][]

Basta cambiare type.GetElementType () semplicemente type se quello che stai passando è il tipo di elemento stesso.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top