web-dev-qa-db-fra.com

Comment vérifier si un type fournit un constructeur sans paramètre?

Je voudrais vérifier si un type connu à l'exécution fournit un constructeur sans paramètre. La classe Type n'a rien donné de prometteur, donc je suppose que je dois utiliser la réflexion?

94
mafu

La classe Type est une réflexion . Tu peux faire:

Type theType = myobject.GetType(); // if you have an instance
// or
Type theType = typeof(MyObject); // if you know the type

var constructor = theType.GetConstructor(Type.EmptyTypes);

Il retournera null si un constructeur sans paramètre n'existe pas.


Si vous souhaitez également trouver des constructeurs privés, utilisez le légèrement plus long:

var constructor = theType.GetConstructor(
  BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, 
  null, Type.EmptyTypes, null);

Il y a une mise en garde pour les types de valeur, qui ne sont pas autorisés à avoir un constructeur par défaut . Vous pouvez vérifier si vous avez un type de valeur en utilisant la propriété Type.IsValueType , et créer des instances en utilisant Activator.CreateInstance(Type) ;

157
Alex J
type.GetConstructor(Type.EmptyTypes) != null

échouerait pour structs. Mieux vaut l'étendre:

public static bool HasDefaultConstructor(this Type t)
{
    return t.IsValueType || t.GetConstructor(Type.EmptyTypes) != null;
}

Réussit puisque même enums ont un constructeur sans paramètre par défaut. Accélère également légèrement pour les types de valeur car l'appel de réflexion n'est pas effectué.

13
nawfal

Oui, vous devez utiliser Reflection. Mais vous le faites déjà lorsque vous utilisez GetType()

Quelque chose comme:

var t = x.GetType();
var c = t.GetConstructor(new Type[0]);
if (c != null) ...
12
Henk Holterman

Cela devrait fonctionner:

   myClass.GetType().GetConstructors()
                    .All(c=>c.GetParameters().Length == 0)
8
BrokenGlass

Selon votre situation, vous pouvez également utiliser une restriction de type générique:

public void DoSomethingWith<T>(T myObject) where T:new() {...}

La déclaration de méthode ci-dessus restreindra le type de paramètre à tout objet pouvant être instancié avec un constructeur sans paramètre. L'avantage ici est que le compilateur interceptera toute tentative d'utilisation de la méthode avec une classe qui n'a pas de constructeur sans paramètre, donc tant que le type est connu quelque part au moment de la compilation, cela fonctionnera et vous alertera sur un problème plus tôt.

Bien sûr, si le type n'est vraiment connu qu'au moment de l'exécution (c'est-à-dire que vous utilisez Activator.CreateInstance () pour instancier un objet basé sur une chaîne ou un type construit), cela ne vous aidera pas. J'utilise généralement la réflexion comme la dernière option absolue, car une fois que vous êtes allé sur une terre dynamique, vous devez à peu près rester dans une terre dynamique; il est généralement difficile, voire plus compliqué, d'instancier dynamiquement quelque chose, puis de commencer à le traiter statiquement.

4
KeithS

Si quelqu'un est intéressé par une version "officielle", ce qui suit a été trouvé via . NET Reflector :

de: System.Activities.Presentation.TypeUtilities
dans System.Activities.Presentation.dll, Version = 4.0.0.0

public static bool CanCreateInstanceUsingDefaultConstructor(this Type t) => 
                t.IsValueType || !t.IsAbstract && t.GetConstructor(Type.EmptyTypes) != null;

Remarquez le chèque pour t.IsAbstract, qui n'est pas mentionné ailleurs sur cette page.

Vous pouvez également développer l'appel GetConstructor comme suit, si vous souhaitez micro-optimiser une trame de pile:

…t.GetConstructor(BindingFlags.Public|BindingFlags.Instance, null, Type.EmptyTypes, null)…
1
Glenn Slayden

Oui, vous devez utiliser la réflexion.

object myObject = new MyType();
Type type = myObject.GetType();
ConstructorInfo conInfo = type.GetConstructor(new Type[0]);
1
Mel Harbour

J'avais besoin de compter les constructeurs avec niquement les paramètres optionnels identiques aux vrais constructeurs sans paramètres. Pour faire ça:

myClass.GetType().GetConstructors()
    .All(c => c.GetParameters().Length == 0 || c.GetParameters().All(p => p.IsOptional))
1
Aaron D