Wie kann ich eine Instanz eines beliebigen Array-Typs zur Laufzeit erstellen?
-
03-07-2019 - |
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.
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 werdenvar 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.