Exploitation de la réflexion dans la plateforme .NET

Décembre 2016


Introduction


L’espace de nom « System.Reflection» du Framework .NET nous permet de décortiquer un Assembly (un Assembly c’est un projet) et de savoir par exemple : quel est la liste des champs, des propriétés ou des méthodes que contiennent les classes de cet Assembly.

Pré-requis


On suppose que nos lecteurs ont un minimum de connaissances avec la plateforme .NET et avec les WinForms. On outre, on note qu’on se base dans notre exemple sur le Framework.NET 3.5 avec l’IDE Microsoft Visual Studio 2008.

Création du projet et des éléments à exploiter


En ce qui suit nos choix lors de la création de notre projet.

Création du projet


On commence par choisir un projet de type « Windows Forms Application ». On note très bien aussi le choix du « .NET Framework 3.5 ».



Une fois le projet créé vous allez trouvez une WinForms déjà ajoutée « Form1 ».

Maintenant ajouter une classe à votre projet « Shift + Alt + c »



Dans la Classe1 ajouter les champs suivant :
 private string champsTest1 = string.Empty;
        private string champsTest2 = string.Empty;

Puis les proprieties suivantes:
  public string ChampsTest1
        {
            get { return champsTest1; }
            set { champsTest1 = value; }
        }

        public string ChampsTest2
        {
            get { return champsTest2; }
            set { champsTest2 = value; }
        }

Puis les méthodes suivantes:
   public string Method1()
        {
            return string.Empty;
        }

        public string Method2()
        {
            return string.Empty;
        }

Maintenant allez dans la Form1 et ajouter un bouton, et insérer le code suivant dans son événement click :

private void button1_Click(object sender, EventArgs e)
        {
            // En prmier lieu on fait un appel qui est en cour d'éxécution
            Assembly asm = Assembly.GetExecutingAssembly();
            // On va choisir la classe Class1 pour la décortiquer, en allant chercher son type 
            System.Type type = asm.GetType("Test.Class1");

            // on demande au Type de nous retourner la liste des champs qu'il contient 
            string strFields = "Liste des fileds : rn";
            foreach (FieldInfo fi in type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance))
                strFields += fi.Name + " : " + fi.FieldType.Name + ", ";

            // on demande au Type de nous retourner la liste des méthodes qu'il contient 
            string strMethods = "rnrn Liste des méthodes : rn";
            foreach (MethodInfo mi in type.GetMethods())
                strMethods += mi.Name + " : " + mi.ReturnType.Name + ", ";

            // on demande au Type de nous retourner la liste des propriétés qu'il contient 
            string strProperties = "rnrn Liste des propriétés : rn";
            foreach (PropertyInfo pi in type.GetProperties())
                strProperties += pi.Name + " : " + pi.PropertyType.Name + ", ";

            MessageBox.Show(strFields + strMethods + strProperties);
        }

N’oubliez pas de rajouter l’instruction suivante dans votre forme :

using System.Reflection;


Exécuter votre projet et appuyer sur le bouton de votre forme : vous allez avoir une liste des champs, des propriétés et des méthodes que contient la classe Class1. Le plus important est que tout le processus se déroule d’une façon générique, en aucun cas on a été obligé d’instancier notre classe et d’aller chercher ces propriétés, ces champs ou ces méthode d’une façon classique.

Utilisation de la réflexion


Supposons que nous utilisons la Class1 comme support de donnée pour aller après les insérer dans une base de donnée et nous voulons être sur que lors de la validation de cette insertion toutes les propriétés de la Class1 qui sont obligatoires doivent avoir une valeur, sauf que nous voulons faire cette vérification d’une façon générique. Pour cela nous allons utiliser l’espace de nom « System.Reflection» et l’espace de nom « System.ComponentModel » qui nous permettra d’ajouter des données statiques à notre classe à partir des attributs.

Dans votre Class1 ajouter l’instruction suivante :

using System.ComponentModel;


Puis remplacer les deux propriétés de votre classe par les propriétés suivante :

[Description("description du champsTest1")]
        public string ChampsTest1
        {
            get { return champsTest1; }
            set { champsTest1 = value; }
        }

        [Description("description du champsTest2"), Category("Mandatory")]
        public string ChampsTest2
        {
            get { return champsTest2; }
            set { champsTest2 = value; }
        }


Vous remarquez qu’on à rajouter des attributs à nos propriétés : l’attribut « Description » et l’attribut « Category ». Nous allons maintenant supposer que toutes les propriétés qui possèdent un attribut « Category » avec une valeur « Mandatory » doivent obligatoirement avoir une valeur non nulle.

L’affectation des attributs peut se faire pour les classes, les propriétés, les champs et les méthodes, dans un autre cas d’utilisation nous pourrons créer nos propres attribut (exemple : créer un attribut « Persist » qui sera affecter aux propriétés d’une classe et dont la valeur servira à identifier dans quel champs de la base de donnée insérer la valeur de notre propriété, et à partir de là on aura la possibilité de générer des requêtes d’insertion d’une façon complètement automatisée.

Maintenant allez dans la Form1 et ajouter un bouton, et insérer le code suivant dans son événement click :

 private void button2_Click(object sender, EventArgs e)
        {
            // En prmier lieu on fait un appel qui est en cour d'éxécution
            Assembly asm = Assembly.GetExecutingAssembly();
            // On va choisir la classe Class1 pour la décortiquer, en allant chercher son type 
            System.Type type = asm.GetType("Test.Class1");
            // on peut utiliser la reflection pour instancier une classe 
            object o = asm.CreateInstance("Test.Class1");
            // on peut utiliser la reflection pour modifier la valeur d'une propriété 
            PropertyInfo pi = type.GetProperty("ChampsTest1");
            pi.SetValue(o, "nouvelle valeur", null);
            // on peut utiliser la reflection pour modifier la valeur d'une propriété 
            pi = type.GetProperty("ChampsTest2");
            pi.SetValue(o, null, null);

            // on demande au Type de nous retourner la liste des propriétéz qu'il contient 
            string strVerification = string.Empty;
            foreach (PropertyInfo piv in type.GetProperties())
            {
                // pour chaque propriété on verifie si elle possede un attribut de type Category
                foreach(object oatt in piv.GetCustomAttributes(typeof(System.ComponentModel.CategoryAttribute),true))
                {
                    // si elle en possède un on va chercher sa description dans l'attribut Description
                    // pour pouvoir formuler notre alerte correctement
                    System.ComponentModel.CategoryAttribute att =(System.ComponentModel.CategoryAttribute)oatt;
                    if(att.Category == "Mandatory")
                    {
                        object[] lo = piv.GetCustomAttributes(typeof(System.ComponentModel.DescriptionAttribute), true);
                        System.ComponentModel.DescriptionAttribute datt = (System.ComponentModel.DescriptionAttribute)lo[0];
                        strVerification +=  "La valeur de la propriété " + datt.Description + " est obligatoire";
                    }
                }
            }

            MessageBox.Show(strVerification);
}


Dans cet exemple on a procédé de la manière suivante.
1 - Utiliser la réflexion pour aller chercher l’ « Assembly » qui est en exécution grâce à la méthode « GetExecutingAssembly ».
2 – Atteindre un type de cet « Assembly » grâce à la méthode « GetType ».
3 – Instancier cette classe d’une façon générique grâce à la méthode « CreateInstance ».
4 – Atteindre une propriété de cette classe grâce à la classe « PropertyInfo» qui nous donne beaucoup de possibilités de manipuler notre propriété, comme lui affecter une valeur grâce à la méthode « SetValue » ou lire la valeur de la propriété grâce à la méthode « GetValue ».
5 – Mais surtout lire les attributs des propriétés de notre classe et savoir lesquelles présentent une obligation de valeur non nulle et générer des messages d’alerte et tout cela d’une façon générique.

Conclusion


Cet article présente un premier contact avec l’espace de nom « System.Reflection». Ce qu’il faut retenir est que désormais il est possible de manipuler des « Assembly », des « Type » et des « Instance » d’une façon complètement générique.

A voir également :

Ce document intitulé «  Exploitation de la réflexion dans la plateforme .NET  » issu de CommentCaMarche (www.commentcamarche.net) est mis à disposition sous les termes de la licence Creative Commons. Vous pouvez copier, modifier des copies de cette page, dans les conditions fixées par la licence, tant que cette note apparaît clairement.