2008-09-26 7 views
58

Quel est le moyen le plus efficace d'obtenir le constructeur par défaut (constructeur d'instance sans paramètre) d'un System.Type? Je pensais à quelque chose comme le code ci-dessous, mais il semble qu'il devrait y avoir une façon plus simple et plus efficace de le faire.Méthode la plus efficace pour obtenir le constructeur par défaut d'un type

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

Répondre

112
type.GetConstructor(Type.EmptyTypes) 
+6

les membres statiques que vous ne regardez jamais ... c'est génial. –

+1

Les membres privés ne sont pas regardés non plus.En supposant que vous avez seulement besoin de public, cela semble être le plus simple. Cependant, est-ce le plus rapide? Je travaille sur un test en ce moment pour le savoir. –

+6

Après avoir mesuré cette approche par rapport à mon approche en utilisant MeasureIt (http://msdn.microsoft.com/en-us/magazine/cc500596.aspx) cette approche est plus rapide dans tous les cas sauf les plus simples et même alors, il est à peine plus lent. Donc, c'est à la fois le plus simple et le plus rapide. Merci! –

28

Si vous avez réellement besoin l'objet ConstructorInfo, puis voir Curt Hagenlocher's answer.

D'autre part, si vous êtes vraiment juste essayer de créer un objet à l'exécution d'un System.Type, voir System.Activator.CreateInstance - il n'y a pas que l'avenir récolement (poignées Activator plus de détails que ConstructorInfo.Invoke), il est également beaucoup moins moche.

+2

Conseil potentiellement dangereux, car certains objets n'ont pas de constructeurs par défaut (String étant un). Donc, si vous appelez cela simplement bon gré mal gré, vous pourriez vous retrouver avec une exception MissingMethod. Je dois en fait vérifier un constructeur par défaut avant d'appeler cette méthode. – cunningdave

+0

Comme écrit cunningdave, vous voudrez probablement attraper et gracieusement au moins une partie de l'ensemble d'exceptions qui peuvent être levées par cette méthode, ce qui rendrait l'appel beaucoup moins beau à nouveau. La solution avec ConstructorInfo, d'autre part, semble en fait plutôt laide, mais vous permet de gérer tous ces cas exceptionnels sans jeter et attraper les exceptions d'abord, ce qui peut être une chose coûteuse. – buygrush

-2

vous voulez essayer FormatterServices.GetUninitializedObject (type) celui-ci est mieux que Activator.CreateInstance

Cependant, cette méthode ne remet pas le constructeur de l'objet, donc si vous définissiez les valeurs initiales là, ce ne fonctionnera pas Vérifiez MSDN pour cette chose http://msdn.microsoft.com/en-us/library/system.runtime.serialization.formatterservices.getuninitializedobject.aspx

il y a une autre façon ici http://www.ozcandegirmenci.com/post/2008/02/Create-object-instances-Faster-than-Reflection.aspx

mais celui-ci échoue si l'objec t ont des constructeurs de paramètrer

Hope this helps

0

Si vous voulez seulement obtenir le constructeur par défaut pour instancier la classe, et obtenez le type comme un paramètre de type générique à une fonction, vous pouvez effectuer les opérations suivantes:

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

Ou juste 'nouveau T()' lol –

1

Si vous avez le paramètre de type générique, la réponse de Jeff Bridgman est la meilleure. Si vous n'avez qu'un objet Type représentant le type que vous voulez construire, vous pouvez utiliser Activator.CreateInstance(Type) comme Alex Lyman l'a suggéré, mais on m'a dit qu'il est lent (je ne l'ai pas profilé personnellement cependant).

Cependant, si vous vous trouvez la construction de ces objets très souvent, il y a une approche plus éloquente en utilisant compilés dynamiquement Linq expressions:

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

Il suffit d'appeler le délégué retourné. Vous devriez mettre ce délégué en cache, car il peut être coûteux de recompiler constamment des expressions Linq, mais si vous mettez en cache le délégué et que vous le réutilisez à chaque fois, cela peut être très rapide! J'utilise personnellement un dictionnaire de recherche statique indexé par type. Cette fonction est pratique lorsque vous traitez des objets sérialisés dans lesquels vous ne connaissez que les informations de type.

REMARQUE: Ceci peut échouer si le type n'est pas constructible ou n'a pas de constructeur par défaut!