web-dev-qa-db-fra.com

Le moyen le plus efficace d'obtenir le constructeur par défaut d'un type

Quel est le moyen le plus efficace d’obtenir le constructeur par défaut (c’est-à-dire un constructeur d’instance sans paramètre) d’un System.Type?

Je pensais quelque chose dans le sens du code ci-dessous, mais il semble qu'il devrait y avoir un moyen plus simple et plus efficace de le faire.

Type type = typeof(FooBar)
BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
type.GetConstructors(flags)
    .Where(constructor => constructor.GetParameters().Length == 0)
    .First();
63
Wes Haggard
type.GetConstructor(Type.EmptyTypes)
121
Curt Hagenlocher

Si vous avez réellement besoin l'objet ConstructorInfo, consultez la réponse de Curt Hagenlocher .

D'un autre côté, si vous essayez vraiment de créer un objet au moment de l'exécution à partir d'un System.Type, consultez System.Activator.CreateInstance - il n'est pas seulement prêt pour le futur (Activator gère plus de détails que ConstructorInfo.Invoke), mais aussibeaucoup moins moche.

29
Alex Lyman

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

Cependant, si vous construisez très fréquemment ces objets, il existe une approche plus éloquente qui utilise des expressions Linq compilées de manière dynamique:

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é qui vous est revenu. Vous devriez mettre en cache ce délégué, car recompiler constamment des expressions Linq peut coûter cher, mais si vous mettez en cache le délégué et le réutilisez à chaque fois, cela peut être très rapide! Personnellement, j'utilise un dictionnaire de recherche statique indexé par type. Cette fonction est pratique lorsque vous traitez avec des objets sérialisés pour lesquels vous ne connaissez peut-être que les informations de type.

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

2
DaFlame

Si vous souhaitez uniquement que le constructeur par défaut instancie la classe et obtenez le type en tant que paramètre de type générique pour une fonction, vous pouvez procéder comme suit:

T NewItUp<T>() where T : new()
{
   return new T();
}
0
Jeff Bridgman