Réflexion et types génériques

J’écris du code pour un constructeur de classe qui parcourt toutes les propriétés de la classe et appelle une méthode statique générique qui remplit ma classe avec les données d’une API externe. Donc, j’ai ceci comme exemple de classe:

public class MyClass{ public ssortingng Property1 { get; set; } public int Property2 { get; set; } public bool Property3 { get; set; } public static T DoStuff(ssortingng name){ // get the data for the property from the external API // or if there's a problem return 'default(T)' } } 

Maintenant, dans mon constructeur, je veux quelque chose comme ça:

 public MyClass(){ var properties = this.GetType().GetProperties(); foreach(PropertyInfo p in properties){ p.SetValue(this, DoStuff(p.Name), new object[0]); } } 

Ainsi, le constructeur ci-dessus générera une erreur car je ne fournis pas le type générique.

Alors, comment puis-je passer dans le type de la propriété?

Voulez-vous appeler DoStuff avec T = le type de chaque propriété? Dans ce cas, “tel quel”, vous devrez utiliser la reflection et MakeGenericMethod – c’est-à-dire

 var properties = this.GetType().GetProperties(); foreach (PropertyInfo p in properties) { object value = typeof(MyClass) .GetMethod("DoStuff") .MakeGenericMethod(p.PropertyType) .Invoke(null, new object[] { p.Name }); p.SetValue(this, value, null); } 

Cependant, ce n’est pas très joli. En réalité, je me demande si ce ne serait pas mieux d’avoir simplement:

 static object DoStuff(ssortingng name, Type propertyType); ... and then object value = DoStuff(p.Name, p.PropertyType); 

Que vous donnent les génériques dans cet exemple? Notez que les types de valeur seront toujours mis en boîte, etc. pendant l’appel de reflection – et même dans ce cas, la boxe n’est pas aussi mauvaise que vous pourriez le penser .

Enfin, dans de nombreux scénarios, TypeDescriptor.GetProperties () est plus approprié que Type.GetProperties () – permet des modèles d’object souples, etc.

Votre code constructeur était-il censé se lire comme ceci:

 public MyClass(){ var properties = this.GetType().GetProperties(); foreach(PropertyInfo p in properties){ p.SetValue(this, DoStuff(p.Name), new object[0]); } } 

? Notez le DoStuff au lieu de MyClass .

Si tel est le cas, le problème est que vous essayez d’utiliser des génériques alors qu’ils ne sont vraiment pas applicables. Le but des génériques (enfin, l’un des points) est d’utiliser la sécurité de type compilation. Ici, vous ne connaissez pas le type au moment de la compilation! Vous pouvez appeler la méthode par reflection (récupérer le formulaire ouvert puis appeler MakeGenericMethod ), mais c’est plutôt moche.

DoStuff doit- DoStuff vraiment être générique en premier lieu? Est-il utilisé ailleurs? Le paramètre de PropertyInfo.SetValue est simplement object, vous obtiendrez donc la boxe, etc. même si vous pouviez appeler la méthode de manière générique.

Si vous n’utilisez pas DoStuff depuis un autre endroit, je suggère également d’écrire une méthode non générique.

Peut-être avez-vous créé la méthode générique pour pouvoir utiliser la valeur par défaut (T). Pour remplacer cela dans une méthode non générique, vous pouvez utiliser Activator.CreateInstance (T) pour les types valeur et null pour les types référence:

 object defaultResult = type.IsValueType ? Activator.CreateInstance(type) : null