2008-09-26 5 views
58

zu erhalten Was ist der effizienteste Weg, um den Standardkonstruktor (d. H. Instanzkonstruktor ohne Parameter) eines System.Type zu erhalten?Der effizienteste Weg, Standardkonstruktor eines Typs

Ich dachte etwas in Richtung des unten stehenden Codes, aber es scheint, dass es einen einfacheren, effizienteren Weg geben sollte.

Type type = typeof(FooBar) 
BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; 
type.GetConstructors(flags) 
    .Where(constructor => constructor.GetParameters().Length == 0) 
    .First(); 

Antwort

112
type.GetConstructor(Type.EmptyTypes) 
+6

die statischen Mitglieder, die Sie nur nie anschauen ... das ist genial. –

+1

Private Mitglieder werden auch nicht angesehen.Angenommen, Sie brauchen nur öffentlich, dann scheint dies die einfachste zu sein. Aber ist es am schnellsten? Ich arbeite gerade an einem Test, um es herauszufinden. –

+6

Nach einigen Messungen dieses Ansatzes gegenüber meinem Ansatz mit MeasureIt (http://msdn.microsoft.com/en-us/magazine/cc500596.aspx) ist dieser Ansatz in allen außer den einfachsten Fällen schneller und selbst dann ist es kaum langsamer. Das ist also sowohl das Einfachste als auch das Schnellste. Vielen Dank! –

28

Wenn Sie tatsächlich Notwendigkeit das ConstructorInfo Objekt, dann Curt Hagenlocher's answer sehen.

Auf der anderen Seite, wenn Sie wirklich nur ein Objekt zur Laufzeit von einem System.Type zu schaffen versuchen, sehen System.Activator.CreateInstance - es ist nicht nur zukunftssicher (Activator Griffe mehr Details als ConstructorInfo.Invoke), ist es auch viel weniger hässlich.

+2

Möglicherweise gefährliche Ratschläge, weil bestimmte Objekte keine Standardkonstruktoren haben (String ist eins). Also, wenn Sie dies nur willy-nilly nennen, könnten Sie mit einer MissingMethod-Ausnahme enden. Ich muss tatsächlich nach einem Standardkonstruktor suchen, bevor ich diese Methode aufrufen kann. – cunningdave

+0

Wie cunningdave schreibt, möchten Sie höchstwahrscheinlich mindestens einen Teil der Ausnahmebedingung, die durch diese Methode ausgelöst wird, abfangen und elegant verarbeiten, wodurch der Aufruf wieder viel weniger schön würde. Die Lösung mit ConstructorInfo auf der anderen Seite sieht zunächst wirklich hässlich aus, erlaubt Ihnen aber, alle diese Ausnahmefälle zu behandeln, ohne zuerst Ausnahmen zu werfen und abzufangen, was eine kostspielige Sache sein kann. – buygrush

-2

würden Sie wollen, um zu versuchen FormatterServices.GetUninitializedObject (Type) dieses ist besser als Activator.CreateInstance

Dieses Verfahren ist jedoch nicht das Objekt Konstruktor nicht aufrufen, wenn Sie also dort Anfangswerte setzen, diese nicht MSDN Überprüfen Sie arbeiten für diese Sache http://msdn.microsoft.com/en-us/library/system.runtime.serialization.formatterservices.getuninitializedobject.aspx

es eine andere Art und Weise http://www.ozcandegirmenci.com/post/2008/02/Create-object-instances-Faster-than-Reflection.aspx

jedoch versagt diese ein, wenn der objec hier t parametrisieren Konstrukteuren

Hoffnung haben, das hilft

0

Wenn Sie nur den Standard-Konstruktor erhalten möchten die Klasse zu instanziiert und werden immer den Typ als generischer Typ Parameter einer Funktion, können Sie folgendes tun:

T NewItUp<T>() where T : new() 
{ 
    return new T(); 
} 
+3

Oder nur 'new T()' lol –

1

Wenn Sie den generischen Typparameter haben, dann ist die Antwort von Jeff Bridgman die beste. Wenn Sie nur ein Type-Objekt haben, das den Typ darstellt, den Sie konstruieren möchten, könnten Sie Activator.CreateInstance(Type) verwenden, wie Alex Lyman vorgeschlagen hat, aber mir wurde gesagt, dass es langsam ist (ich habe es jedoch nicht persönlich profiliert).

Wenn Sie jedoch selbst diese Objekte konstruieren finden sehr häufig gibt es einen beredter Ansatz dynamisch kompiliert Linq-Ausdrücke verwenden:

using System; 
using System.Linq.Expressions; 

public static class TypeHelper 
{ 
    public static Func<object> CreateDefaultConstructor(Type type) 
    { 
     NewExpression newExp = Expression.New(type); 

     // Create a new lambda expression with the NewExpression as the body. 
     var lambda = Expression.Lambda<Func<object>>(newExp); 

     // Compile our new lambda expression. 
     return lambda.Compile(); 
    } 
} 

Rufen Sie die Delegierten an Sie zurückgeschickt. Sie sollten diesen Delegaten zwischenspeichern, da das wiederholte Neukompilieren von Linq-Ausdrücken teuer sein kann, aber wenn Sie den Delegat zwischenspeichern und jedes Mal erneut verwenden, kann er sehr schnell sein! Ich persönlich benutze ein statisches Nachschlagewörterbuch, das nach Typ indiziert ist. Diese Funktion ist praktisch, wenn Sie mit serialisierten Objekten arbeiten, bei denen Sie nur die Typinformationen kennen.

HINWEIS: Dies kann fehlschlagen, wenn der Typ nicht konstruierbar ist oder keinen Standardkonstruktor hat!