64 votes

Comment Reflection ne pourrait-il pas conduire à des odeurs de code?

Je viens de faible niveau de langues - C++ est le plus haut niveau je programme en.

Récemment je suis tombé sur la Réflexion, et je n'arrive pas à imaginer comment il pourrait être utilisé sans odeurs de code.

L'idée de l'inspection d'une classe/méthode/fonction au cours de l'exécution, à mon avis, points à un défaut dans la conception, je pense que la plupart des problèmes de Réflexion (tente de) résoudre peut être utilisé avec le Polymorphisme ou à la bonne utilisation de l'héritage.

Suis-je tort? Dois-je mal compris le concept et l'utilité de la Réflexion?

Je suis à la recherche d'une bonne explication quand à utiliser Réflexion où d'autres solutions d'échouer ou d'être trop lourde à mettre en œuvre ainsi que quand ne PAS utiliser.

Veuillez éclairer ce faible niveau de foi.

90voto

Juliet Points 40758

La réflexion est le plus couramment utilisé pour contourner le système de type statique, mais il a aussi quelques intéressantes cas d'utilisation:

Nous allons écrire un ORM!

Si vous êtes familier avec NHibernate ou la plupart des autres Orm, vous écrire des classes qui correspondent à des tables dans votre base de données, quelque chose comme ceci:

// used to hook into the ORMs innards
public class ActiveRecordBase
{
    public void Save();
}

public class User : ActiveRecordBase
{
    public int ID { get; set; }
    public string UserName { get; set; }
    // ...   
}

Comment pensez-vous que l' Save() méthode qui est écrit? Ainsi, dans la plupart des Orm, la méthode Save ne sais pas quels sont les champs dans les classes dérivées, mais il peut accéder à l'aide de la réflexion.

Sa filiale possible d'avoir les mêmes fonctionnalités dans un type de la sécurité, tout simplement par l'intervention d'un utilisateur de remplacer une méthode pour copier des champs dans un objet datarow, mais qui aurait pour résultat beaucoup de code réutilisable et le ballonnement.

Les talons!

Rhino se moque de est un moqueur cadre. Vous passez d'un type d'interface dans une méthode, et derrière les coulisses, le cadre construire de façon dynamique et instancier un objet fantaisie la mise en œuvre de l'interface.

Bien sûr, un programmeur peut écrire du code réutilisable pour la maquette de l'objet à la main, mais pourquoi serait-elle si le cadre va le faire pour elle?

Les métadonnées!

Nous pouvons décorer les méthodes avec des attributs (métadonnées), qui peuvent servir à diverses fins:

[FilePermission(Context.AllAccess)]    // writes things to a file
[Logging(LogMethod.None)]              // logger doesn't log this method
[MethodAccessSecurity(Role="Admin")]   // user must be in "Admin" group to invoke method
[Validation(ValidationType.NotNull, "reportName")] // throws exception if reportName is null
public void RunDailyReports(string reportName) { ... }

Vous avez besoin de réfléchir sur la méthode d'inspecter les attributs. La plupart des AOP de cadres de .NET utiliser des attributs pour la politique de l'injection.

Bien sûr, vous pouvez écrire le même genre de code en ligne, mais ce style est plus déclaratif.

Nous allons faire un dépendance!

De nombreux Cio conteneurs exigent un certain degré de réflexion pour fonctionner correctement. Par exemple:

public class FileValidator
{
    public FileValidator(ILogger logger) { ... }
}

// client code
var validator = IoC.Resolve<FileValidator>();

Notre conteneur IoC va instancier un fichier de programme de validation et de passer à une mise en œuvre appropriée de ILogger dans le constructeur. Quelle mise en œuvre? Tout dépend de ce que sa mise en œuvre.

Disons que j'ai donné le nom de l'assemblée et de la classe dans un fichier de configuration. La langue a besoin de lire le nom de la classe comme une chaîne de caractères et utiliser la réflexion pour l'instancier.

Si nous ne savons la mise en œuvre au moment de la compilation, il n'y a pas de type de moyen sûr d'instancier une classe basée sur son nom.

La Liaison Tardive / Duck-Typing

Il y a toutes sortes de raisons pourquoi vous voulez lire les propriétés d'un objet lors de l'exécution. Je choisirais l'exploitation forestière comme l'utilisation la plus simple, disons que vous avez écrit un enregistreur qui accepte n'importe quel objet et crache toutes ses propriétés d'un fichier.

public static void Log(string msg, object state) { ... }

Vous pourriez remplacer la méthode Log pour tous les types statiques, ou vous pouvez simplement utiliser la réflexion pour lire les propriétés de la place.

Certains langages comme OCaml et de la Scala de soutien de manière statique vérifié duck-typing (appelé structurels de frappe), mais parfois vous n'avez tout simplement pas le temps de compilation des connaissances de l'un des objets de l'interface.

Ou que les programmeurs Java savez, parfois, le type de système de votre chemin et vous obligent à écrire toutes sortes de code réutilisable. Il y a un article bien connu qui explique comment de nombreux modèles de conception sont simplifiées grâce au typage dynamique.

Parfois contourner le type de système permet de restructurer le code vers le bas beaucoup plus loin que ce qui est possible avec les types statiques, résultant en un peu plus propre code (de préférence caché derrière un sympathique programmeur API :) ). De nombreux statique modernes langues sont l'adoption de la règle d'or "typage statique, si possible, typage dynamique si nécessaire", permettant à des utilisateurs de commuter entre statique et dynamique de code.

11voto

Aaronaught Points 73049

Des projets tels que hibernate (mappage O/R) et de StructureMap (dependency injection) serait impossible sans Réflexion. Comment pourrait-on résoudre ces avec le polymorphisme seul?

Ce qui rend ces problèmes si difficiles à résoudre de toute autre manière, c'est que les bibliothèques ne sont pas directement en sais rien au sujet de votre hiérarchie de classe, ils ne peuvent pas. Et pourtant, ils ont besoin de connaître la structure de vos classes pour - par exemple - carte arbitraire en ligne de données à partir d'une base de données d'une propriété dans votre classe en utilisant uniquement le nom du domaine et le nom de votre propriété.

La réflexion est particulièrement utile pour la cartographie des problèmes. L'idée de la convention sur le code devient de plus en plus et de plus en plus populaire et vous avez besoin d'un certain type de Réflexion à faire.

Dans .NET 3.5+ vous avez une alternative, qui consiste à utiliser des arbres d'expression. Ces sont fortement typées, et de nombreux problèmes qui ont été classiquement résolu à l'aide de Réflexion ont été mis en œuvre à l'aide de lambda et des arbres d'expression (voir Couramment NHibernate, Ninject). Mais gardez à l'esprit que chaque langue prend en charge ces types de constructions; quand ils ne sont pas disponibles, vous êtes essentiellement coincé avec la Réflexion.

Dans un sens (et j'espère que je ne suis pas ébouriffant trop de plumes), la Réflexion est très souvent utilisé comme une solution de contournement/hack dans les langages Orientés Objet pour les fonctions qui entrent gratuitement dans les langages Fonctionnels. Comme les langages fonctionnels deviennent de plus en plus populaire, et/ou plus OO langues commencer à mettre en œuvre plus de fonctionnalités (comme le C#), nous allons très probablement commencer à voir la Réflexion de moins en moins utilisée. Mais je pense qu'elle le fera encore et toujours, pour plus d'applications classiques comme des plugins (comme celui des autres intervenants obligeamment indiqué).

8voto

Damien Pollet Points 3254

En fait, vous êtes déjà à l'aide d'un réfléchissantes système de tous les jours: de votre ordinateur.

Bien sûr, au lieu de classes, de méthodes et d'objets, il a des programmes et des fichiers. Les programmes de créer et de modifier des fichiers tout comme les méthodes de créer et de modifier des objets. Mais les programmes sont les fichiers eux-mêmes, et certains des programmes d'inspecter ou de créer d'autres programmes!

Alors, pourquoi est-il si OK pour une installation de Linux à être réflexif que personne ne pense à ce sujet, et effrayant pour OO programmes?

6voto

Alexandre Jasmin Points 18067

Sans réflexion, vous avez souvent à répéter vous-même beaucoup.

Tenir compte de ces scénarios:

  • Exécuter un ensemble de méthodes, par exemple la testXXX() méthodes dans un cas de test
  • Générer une liste de propriétés dans un gui builder
  • Faire vos classes scriptable
  • Mettre en œuvre un régime de la sérialisation

Vous pouvez généralement pas faire ces choses en C/C++, sans répéter l'ensemble de la liste des méthodes et des propriétés d'autre part dans le code.

En fait, programmeurs C/C++ ont souvent recours à une Interface de langage de description d'exposer des interfaces lors de l'exécution (fournir une forme de réflexion).

L'utilisation judicieuse de réflexion et d'annotations combiné avec bien défini des conventions de codage peuvent évite rampante de la répétition de code et d'augmenter la maintenabilité.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X