Quand utilisez-vous la reflection? Patterns / anti-patterns

Je comprends l’API de reflection (en c #) mais je ne sais pas dans quelle situation l’utiliser. Quels sont certains modèles – anti-modèles pour utiliser la reflection?

Le seul endroit où j’ai utilisé les éléments de Reflection dans C # était dans les modèles d’usine, où je créais des objects (dans mon cas, des écouteurs de réseau) en fonction des informations du fichier de configuration. Le fichier de configuration fournissait l’emplacement des assemblys, le nom des types qu’ils contiennent et les arguments supplémentaires nécessaires. L’usine a pris ce matériel et a créé les auditeurs à partir de cela.

Dans un produit sur lequel je travaille, nous l’utilisons beaucoup, mais Reflection est une bête complexe et lente. Ne cherchez pas des endroits pour l’utiliser simplement parce que cela semble amusant ou intéressant. Vous l’utiliserez lorsque vous rencontrez un problème qui ne peut pas être résolu autrement (chargement dynamic d’assemblages pour des plug-ins ou des infrastructures, inspection d’assemblage, usines où les types ne sont pas connus à la construction, etc.). Cela vaut certainement la peine de regarder des tutoriels de reflection pour voir comment cela fonctionne, mais ne tombez pas dans le piège du “avoir un marteau et tout ce qui ressemble à un clou”. Il a des cas d’utilisation très spécialisés.

Je ne sais pas s’il s’agit d’un modèle, mais j’utilise la reflection pour générer du code SQL à partir des définitions de classe de DAO.

J’ai utilisé la reflection dans plusieurs endroits. Les principales catégories comprennent:

  1. Des interfaces graphiques générées automatiquement (c.-à-d. Un éditeur de propriétés). Vous pouvez effectuer une boucle sur les propriétés d’un object et utiliser un registre de fabriques d’éléments d’interface utilisateur pour créer un formulaire. J’utilise des atsortingbuts sur les propriétés pour guider la création de l’interface utilisateur.
  2. Sérialisation . J’ai écrit des frameworks de sérialisation qui utilisent la reflection pour sérialiser et désérialiser des objects.
  3. Services Web . À l’instar de la sérialisation, j’ai utilisé la reflection pour créer et consumr des messages SOAP, ainsi que pour générer un WSDL.
  4. Langages spécifiques à un domaine . Les langages de script interprétés se lient généralement aux objects et aux méthodes utilisant la reflection.
  5. Outils de débogage . De tels outils peuvent utiliser la reflection pour examiner l’état d’un object. Pratique pour créer des messages de journal dans des conditions d’erreur.

Les modèles sage, je ne suis pas sûr de ce que sont les modèles. Un fil conducteur entre toutes les utilisations est la référence par nom et la liaison tardive – vous souhaitez vous lier à un membre au moment de l’exécution. C’est souvent le cas lorsque vous chargez des assemblages de manière dynamic sans connaître les types d’object que vous devez créer / manipuler.

Utiliser la reflection est puissant, mais cela ne vous rendra pas plus populaire lors des fêtes. Utilisez-le uniquement lorsque le couplage est intentionnellement faible. Si faible que vous vous attendez à ce qu’il casse au moment de l’exécution. Un bon exemple est la liaison de données dans WPF.

Je ne suis pas sûr des anti-patterns, mais cela aurait sûrement un rapport avec l’exécution de tâches qui devraient être faites au moment de la compilation …

Il n’y a pas de règle absolue. Fondamentalement, vous n’utilisez pas la reflection sans une bonne raison. Utilisez la reflection lorsque vous ne pouvez pas faire ce que vous voulez sans elle, ou lorsque votre code serait beaucoup plus long ou plus difficile à comprendre sans reflection.

Je trouve la reflection (combinée avec le chargement de classe d’exécution) indispensable pour la mise en oeuvre de plugins:

  1. rechercher des bocaux / assemblages dans un lieu connu
  2. énumérer les jars / assemblages pour les classes supportant l’interface prise en charge par votre plugin
  3. instancier le plugin au moment de l’exécution

Je ne suis pas sur le sharepoint laisser tomber des modèles, mais je dirais que c’est une bonne idée d’éviter de réfléchir avant d’en avoir réellement besoin. C’est particulièrement utile pour les situations d’interopérabilité et d’extensibilité où vous ne pouvez pas contrôler à l’avance le type d’un object.

Je l’utilise dans un sérialiseur binary ( protobuf-net ). J’utilise la reflection uniquement pour construire le modèle – lorsqu’il est utilisé (c’est-à-dire pendant la [dé] sérialisation), il utilise des delegates, etc. pour des performances maximales.

Je l’ai également utilisé (avec ComponentModel et Reflection.Emit) dans HyperDescriptor , pour créer un access de propriété accéléré (~ 100 fois la vitesse de la reflection régulière).

Et par nécessité, vous devez utiliser la reflection si vous construisez vos propres Expression .

J’utilise beaucoup la reflection dans mes tests unitaires, en particulier lorsque les éléments que je vérifie sont de type anonyme. Je l’ai également utilisé pour cloner / copier facilement des objects de modèle. Plutôt que d’écrire le code pour cela pour chaque object du modèle, je peux facilement créer un object d’un type particulier en utilisant la reflection, interroger les propriétés publiques de l’object entrant et appeler les parameters sur les propriétés correspondantes des objects clonés. Je l’utilise également avec les classes générées par le concepteur qui implémentent les mêmes signatures de méthode, mais ne possèdent pas d’interface associée. Dans ces cas, je peux interroger l’object pour voir s’il dispose de la méthode requirejse et l’invoquer si c’est le cas. Les entités LINQ2SQL ressemblent à cela. Ainsi, dans mon fausse méthode OnSubmit du wrapper de contexte de données, j’utilise la reflection pour obtenir la méthode OnValidate et l’invoquer pour les tests unitaires.

+1 sur l’utilisation du modèle d’usine – très puissant ici.

Mis à part le motif d’usine, chaque fois que je l’utilisais, je n’aurais probablement pas dû …

Je l’ai utilisé pour charger dynamicment les classes qui implémentent certaines interfaces (les miens étaient des éléments de menu des assemblys) au démarrage et je regrette vraiment cette utilisation. J’aurais aimé charger depuis un fichier de configuration (et plus tard, j’ai ajouté un formulaire qui montrait les interfaces disponibles pour être chargées). C’est cool mais terriblement lent …

Un anti-modèle consiste à utiliser les propriétés d’access que les concepteurs de classe ont marquées comme privées sans savoir pourquoi ils les ont marquées comme privées. C’est ce que j’ai fait avec le contrôle DataGridView WinForms pour annuler la définition d’une variable booléenne afin de pouvoir déplacer une colonne “compagnon” lorsque son complément a été déplacé. Encore une fois, c’est très cool, mais ce code échouera horriblement si une nouvelle version modifie cette propriété privée (il pourrait très bien disparaître dans les versions 3.0 ou 3.5 …).

Je suis allé 2 ans de développement sans comprendre le but de la reflection. Il a des utilisations très niches, mais il est extrêmement puissant quand c’est le bon outil pour le poste.

Je pense que ce que j’essaie de dire, c’est de ne l’utiliser que lorsque vous êtes sûr que c’est le seul moyen de réaliser ce que vous voulez.

Je l’utilise dans un cas similaire à celui mentionné par Harper Shelby, dans lequel un fichier de configuration spécifie au moment de l’exécution quel object instancier. Dans mon cas particulier, rien n’est aussi complexe qu’une fabrique – il n’ya qu’un ensemble de classes qui implémentent une interface commune et une fonction simple qui lit le fichier de configuration et crée le bon object, en renvoyant l’interface.

Le premier endroit où j’utilise la reflection: extraire un type d’une firebase database.

J’ai une classe qui a besoin de savoir quelle bibliothèque appeler. N’oubliez pas que, lors de l’ajout de nouveaux outils à la liste, la classe doit les reconnaître sans recomstackr. Par conséquent, une instruction switch est hors de question.

Au lieu de cela, je stocke la chaîne de reflection dans la firebase database qui indique à la classe de “créer l’un de ces …” Etant donné que je (le programmeur) veille toujours à ce que la classe soit dérivée d’une classe de base unique, l’idée fonctionne. C’est propre et efficace.

Mais je conviens que si vous utilisez la reflection pour plus que ces scénarios de “code généré automatiquement”, vous vous exposez à un monde de blessures pour le maintien du code dans le futur.

(entre voix de sage, vieux sage)
La reflection vient avec un pouvoir incroyable … utilisez le pouvoir avec sagesse.

Je l’utilise le plus souvent quand j’ai besoin de casser l’encapsulation de quelqu’un d’autre (généralement celle du framework). C’est-à-dire que je dois modifier un champ privé, appeler une méthode privée ou créer une instance d’une classe interne dans une bibliothèque que je ne peux pas modifier. Un bon exemple est le code dans ma réponse à cette question . Dans ce cas, le comportement de la méthode d’ ServiceBase.Run était inacceptable. J’ai donc utilisé la reflection pour faire la même chose, mais d’une manière plus acceptable.

La reflection a cependant de nombreuses autres utilisations, notamment la saisie à l’aide de canards , l’utilisation d’ atsortingbuts et la liaison tardive .

Reflection vous permet de résoudre des problèmes qui nécessiteraient sinon de dupliquer du code. Si vous vous retrouvez en train de copier-coller du code et que vous ne voyez pas en quoi un modèle OO peut vous aider, peut-être si vous pouvez les appeler, alors l ‘”équipe r” pourra vous aider.

Je plaisante seulement. Je ne pouvais pas comprendre le sharepoint reflection depuis des siècles. Si vous pouvez écrire du code pour effectuer un travail, pourquoi avez-vous besoin d’utiliser la reflection?

Supposons que vous avez beaucoup d’objects d’interface graphique tels que des formulaires ou des objects de type ‘table’ Il se lie à un object métier tel qu’un client:

 public class Customer { public ssortingng FirstName; public ssortingng LastName; } 

Vos utilisateurs ne veulent pas voir les en-têtes de colonne “Prénom” ou “Nom”. Ils veulent le «prénom» et le nom de famille. Vous ne voulez pas coder les chaînes littérales de tous vos objects d’interface graphique au cas où ils changeraient d’avis en ‘Prénom’ et ‘Nom de famille du père’ (je sais, exemple merde).

Si vous définissez votre classe à l’aide d’atsortingbuts:

 public class Customer { [Description("Christian Name")] public ssortingng FirstName; [Description("Surname")] public ssortingng LastName; } 

Vous pouvez utiliser la reflection pour extraire les noms de colonne. Si vous devez modifier la manière dont tous vos objects d’interface graphique décrivent l’object client, vous le faites maintenant au même endroit.

Je ne suis au courant d’aucun anti-modèle. Mon conseil est d’intervenir et d’essayer. Vous allez commencer à voir toutes sortes de façons dont la reflection vous offre une solution élégante. La performance est souvent citée comme une raison de ne pas utiliser la réinfection. La réinfection entraîne un surcoût lié aux performances, mais je ne l’écarterai que si vous pouvez prouver que le surcoût nuit à un algorithme dont vous avez besoin.

Lorsque vous souhaitez améliorer les performances des objects à liaison tardive. Vous pouvez émettre le code nécessaire pour appeler directement les types liés, puis appeler via votre méthode émise. Bien que vous ne puissiez pas effectuer d’appels aussi rapidement qu’avec la liaison anticipée, vous obtiendrez de meilleurs résultats que la liaison tardive.

Personnellement, je ne l’utilise pas beaucoup. J’ai tendance à l’utiliser quand je n’ai pas de manière différente de coder quelque chose.

Voici un exemple simple:

 public static void LogException(Exception exc, ssortingng source) { try { // Logic for logging exceptions } catch(Exception ex) { //If logging fails for some reason //then we still log it using reflection LogException(ex, "Error while logging an exception"); } }