C# Réflexion

La réflexion désigne la capacité d’un programme à accéder à son propre état ou comportement, à l’inspecter et à le modifier.

Les assemblys contiennent des modules, les modules contiennent des types, et les types contiennent des membres. La réflexion fournit des objets qui encapsulent les assemblys, les modules et les types.

Vous pouvez utiliser la réflexion pour créer dynamiquement une instance d’un type, lier le type à un objet existant, ou obtenir le type à partir d’un objet existant. Ensuite, vous pouvez appeler les méthodes du type ou accéder à ses champs et propriétés.

Avantages et inconvénients

Avantages :

  • 1. La réflexion améliore la flexibilité et l’extensibilité des programmes.
  • 2. Elle réduit le couplage et améliore l’auto-adaptabilité.
  • 3. Elle permet aux programmes de créer et de contrôler des objets de n’importe quelle classe sans coder en dur la classe cible à l’avance.

Inconvénients :

  • 1. Problèmes de performance : l’utilisation de la réflexion est essentiellement une opération d’interprétation, qui est beaucoup plus lente que le code direct lors de l’accès aux champs et aux méthodes. Par conséquent, la réflexion est principalement utilisée dans les frameworks système qui exigent une grande flexibilité et extensibilité ; elle n’est pas recommandée pour les programmes ordinaires.
  • 2. L’utilisation de la réflexion masque la logique interne des programmes ; les programmeurs s’attendent à voir la logique du programme dans le code source, mais la réflexion contourne les techniques du code source, ce qui cause des problèmes de maintenance. Le code de réflexion est plus complexe que le code direct équivalent.

Objectif de la réflexion

La réflexion a les utilisations suivantes :

  • Elle permet de consulter les informations d'attribut au moment de l'exécution.
  • Elle permet d'examiner les différents types d'un assembly et d'instancier ces types.
  • Elle permet la liaison tardive des méthodes et des propriétés.
  • Elle permet de créer de nouveaux types au moment de l'exécution, puis d'utiliser ces types pour effectuer certaines tâches.

Afficher les métadonnées

Comme nous l'avons mentionné dans les chapitres précédents, la réflexion peut être utilisée pour afficher les informations d'attribut.

System.ReflectionClasseMemberInfoUn objet doit être initialisé afin de découvrir les attributs associés à la classe. Pour ce faire, vous pouvez définir un objet de la classe cible, comme suit :

System.Reflection.MemberInfo info = typeof(MyClass);

Le programme suivant le démontre :

Exemple

using System;

[AttributeUsage(AttributeTargets.All)]
public class HelpAttribute : System.Attribute
{
   public readonly string Url;

   public string Topic  // Topic est un paramètre nommé
   {
      get
      {
         return topic;
      }
      set
      {

         topic = value;
      }
   }

   public HelpAttribute(string url)  // url est un paramètre de positionnement (positionnel)
   {
      this.Url = url;
   }

   private string topic;
}
[HelpAttribute("Informations sur la classe MyClass")]
class MyClass
{
}

namespace AttributeAppl
{
   class Program
   {
      static void Main(string[] args)
      {
         System.Reflection.MemberInfo info = typeof(MyClass);
         object[] attributes = info.GetCustomAttributes(true);
         for (int i = 0; i < attributes.Longueur; i++)
         {
            System.Console.WriteLine(attributes[i]);
         }
         Console.ReadKey();

      }
   }
}

Lorsque le code ci-dessus est compilé et exécuté, il affichera les attributs attachés à la classeMyClassLes attributs personnalisés sur :

HelpAttribute

Exemple

Dans cet exemple, nous utiliserons ce qui a été créé dans le chapitre précédent.DeBugInfoattributs, et utiliser la réflexion pour les lireRectangleMétadonnées dans la classe.

Exemple

using System;
using System.Reflection;
namespace BugFixApplication
{
   // aCustomFeatures BugFix par赋Giveclass et son membre
   [AttributeUsage(AttributeTargets.Class |
   AttributeTargets.Constructor |
   AttributeTargets.Field |
   AttributeTargets.Method |
   AttributeTargets.Property,
   AllowMultiple = true)]

   public class DeBugInfo : System.Attribute
   {
      private int bugNo;
      private string developer;
      private string lastReview;
      public string message;

      public DeBugInfo(int bg, string dev, string d)
      {
         this.bugNo = bg;
         this.developer = dev;
         this.lastReview = d;
      }

      public int BugNo
      {
         get
         {
            return bugNo;
         }
      }
      public string Developer
      {
         get
         {
            return developer;
         }
      }
      public string LastReview
      {
         get
         {
            return lastReview;
         }
      }
      public string Message
      {
         get
         {
            return message;
         }
         set
         {
            message = value;
         }
      }
   }
   [DeBugInfo(45, "Zara Ali", "12/8/2012",
        Message = "Return type mismatch")]
   [DeBugInfo(49, "Nuha Ali", "10/10/2012",
        Message = "Variable inutilisée")]
   class Rectangle
   {
      // Variables membres
      protected double length;
      protected double width;
      public Rectangle(double l, double w)
      {
         longueur = l;
         width = w;
      }
      [DeBugInfo(55, "Zara Ali", "19/10/2012",
           Message = "Return type mismatch")]
      public double GetArea()
      {
         return length * width;
      }
      [DeBugInfo(56, "Zara Ali", "19/10/2012")]
      public void Display()
      {
         Console.WriteLine("Length: {0}", length);
         Console.WriteLine("Width: {0}", width);
         Console.WriteLine("Area: {0}", GetArea());
      }
   }//fin de la classe Rectangle  
   
   class ExecuteRectangle
   {
      static void Main(string[] args)
      {
         Rectangle r = new Rectangle(4.5, 7.5);
         r.Afficher();
         Type type = typeof(Rectangle);
         // Parcourir les attributs de la classe Rectangle
         foreach (Object attributes in type.GetCustomAttributes(false))
         {
            DeBugInfo dbi = (DeBugInfo)attributes;
            if (null != dbi)
            {
               Console.WriteLine("N° de bug : {0}", dbi.BugNo);
               Console.WriteLine("Développeur : {0}", dbi.Developer);
               Console.WriteLine("Dernière révision: {0}",
                                        dbi.LastReview);
               Console.WriteLine("Remarques: {0}", dbi.Message);
            }
         }
         
         // Fonctionnalités de la méthode d'itération
         foreach (MethodInfo m in type.GetMethods())
         {
            foreach (Attribute a in m.GetCustomAttributes(true))
            {
               DeBugInfo dbi = (DeBugInfo)a;
               if (null != dbi)
               {
                  Console.WriteLine("N° de bug: {0}, pour la méthode: {1}",
                                                dbi.BugNo, m.Name);
                  Console.WriteLine("Développeur : {0}", dbi.Developer);
                  Console.WriteLine("Dernière révision: {0}",
                                                dbi.LastReview);
                  Console.WriteLine("Remarques: {0}", dbi.Message);
               }
            }
         }
         Console.ReadLine();
      }
   }
}

Lorsque le code ci-dessus est compilé et exécuté, il produit les résultats suivants :

Length: 4.5
Width: 7.5
Area: 33.75
Bug No: 49
Developer: Nuha Ali
Last Reviewed: 10/10/2012
Remarks: Unused variable
Bug No: 45
Developer: Zara Ali
Last Reviewed: 12/8/2012
Remarks: Return type mismatch
Bug No: 55, for Method: GetArea
Developer: Zara Ali
Last Reviewed: 19/10/2012
Remarks: Return type mismatch
Bug No: 56, for Method: Display
Developer: Zara Ali
Last Reviewed: 19/10/2012
Remarks: 
autres extensions