Frage

Ich versuche, ein Array von einem Typ unbekannt bei der Kompilierung deserialisieren. Zur Laufzeit habe ich die Art entdeckt, aber ich weiß nicht, wie eine Instanz erstellen.

So etwas wie:

Object o = Activator.CreateInstance(type);

, die nicht funktioniert, weil es kein parameterlosen Konstruktor ist, Array scheint keinen Konstruktor zu haben.

War es hilfreich?

Lösung

Verwenden Sie Array.CreateInstance .

Andere Tipps

Sie können mit einem der Array der CreateInstance Überlastungen z: -.

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

Ganz eine alte Post, aber während eine neue Frage zu beantworten, obwohl ein ähnliches Beispiel für das Erstellen eines mehrdimensionalen Array veröffentlichen.

Unter der Annahme, den Typ (elementType) als int und ein zweidimensionales Array zum Beispiel.

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

Wenn es zweidimensional, zum Beispiel, kann es als

bestückt werden
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 ] ]

Eine Alternative ist Ausdruck Bäume für die Leistung zu verwenden. Für z.B. wenn Sie Array type , type Sie tun können,

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

Das gibt nur ein leeres Array. Wahrscheinlich nicht sehr nützlich. MSDN Staaten GetConstructors jede Bestellung ist keine Garantie, so dass Sie eine Logik benötigen richtigen Konstruktor mit richtigen Parametern mit dem richtigen Größe zu instanziiert zu finden. Für z.B. Sie tun können:

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

Das gleiche mit Expression.NewArrayBounds viel einfacher erreicht werden kann, statt Expression.New, mehr über es funktioniert, wenn alles, was Sie bekommen ist Array Elementtyp, nicht-Array-Typ selbst. 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 type.GetElementType() ändert einfach type wenn, was Sie vorbei Elementtyp selbst.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top