Vos recrutements informatiques

700 000 développeurs, chefs de projets, ingénieurs, informaticiens...

Contactez notre équipe spécialiste en recrutement

Manipulation des attributs en dotnet

A travers cet article nous allons découvrir le système des attributs de dotnet, voir à quoi ils servent, et comment créer ses propres attributs

N'hésitez pas à commenter cet article ! Commentez Donner une note à l'article (5)

Article lu   fois.

L'auteur

Profil ProSite personnel

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

I. Les attributs ? Ké za ko ?

I-A. C'est quoi ?

Un attribut est un petit morceau de code permettant de paramétrer un assembly, une classe, un constructeur, un délégué, une énumération, un événement, un champ, une interface, une méthode, un paramètre, une propriété, une valeur de retour, une structure ou un autre attribut, etc ...
Ils ont une syntaxe praticulière et ne peuvent pas être confondu avec d'autres instructions du langage.

Une classe avec un attribut personnel
Sélectionnez

[MyAttribut(true)]
public class A
{

}

I-B. A quoi ça sert ?

Les attributs servent donc à paramétrer une classe ou autre, afin que les appelant puissent facilement modifier leurs comportements en fonctions de ces paramètres.
Concrètement nous retrouvons les attributs dans beaucoup de classes de l'espace de nom System.Windows.Forms. Les attributs servent par exemple à définir l'image associée à un composant dans les boites à outils de nos EDI préférés.
Un autre attribut que nous rencontrons assez souvent est l'attribut Serializable. Dans ce cas l'attribut sert à "marquer" une classe comme étant sérialisable par le framework.

II. Utiliser les attributs

Maintenant que nous savons ce qu'est un attribut, voyons comment nous pouvons les exploiter dans nos programmes. L'utilisation des attributs est étroitement liée à la reflexion.
En effet c'est grâce à la réflexion que vous allez pouvoir déterminer si une classe, une propriété, un membre possède un ou plusieurs attributs.

Obtenir les attributs d'une classe
Sélectionnez

MyClass myClass = new MyClass();

Type cType = myClass.GetType();
object[] atts = cType.GetCustomAttributes(false); //On obtient les attributs de la classe sans prendre en compte l'héritage

for(int i = 0; i  atts.Length; i++ )
{
   if( atts[i] is CustomAttribut )
   {
		Console.WriteLine( ((CustomAttribut)atts[i]).MyValue );
   }
}

III. Comment créer ses propres attributs ?

Rien n'est plus simple que de créer ces propres attributs. ;-)
Pour cela il suffit de créer une classe dérivant de la classe Attribute de faire terminer le nom de sa classe par Attribute.

Création d'un attribut personnalisé
Sélectionnez

public class CustomAttribute : Attribute
{
	private string myValue;
	
	public CustomAttribute(string myValue)
	{
		this.myValue = myValue;
	}
	
	public string MyValue
	{
		get
		{
			return this.myValue;
		}
	}
}

Cet attribut s'utilise ainsi :

Utilisation du CustomAttribut
Sélectionnez

[Custom("une valeur")]
public class UneClasse
{

}

La valeur définie dans l'attribut lors de son utilisation est obligatoire à cause du constructeur défini la classe CustomAttribute.

III-A. Définition de la porté d'un attribut

Les attributs peuvent être conçu de façon a ce qu'il ne soit valable que sur un certain type de structure de code.
Ainsi un attribut peut être dédié spécialement aux propriétés, aux classes, aux méthodes, etc...
Afin de rendre un attribut spécialisé pour une structure de code il suffit de lui attribuer un ... attribut.

 
Sélectionnez

[AttributeUsage(AttributeTargets.Property)]
public class CustomAttribut
{
	private string myValue;
	
	public CustomAttribute(string myValue)
	{
		this.myValue = myValue;
	}
	
	public string MyValue
	{
		get
		{
			return this.myValue;
		}
	}
}

L'énumération AttributeTargets peut prendre une multitude de valeur. Je vous invite à voir la msdn afin de connaître les possibilités.
Liste des enumérations de l'énumération AttributeTargetsListe des enumérations de l'énumération AttributeTargets
Comment faire pour définir un attribut pouvant être utilisé à la fois sur une propriété et une méthode par exemple ? Il suffit simplement de faire une addition binaire entre toutes les valeurs souhaitées.

 
Sélectionnez

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Method)]

III-B. L'héritage des attributs

Une chose à laquelle on ne pense pas forcément c'est le problème de l'héritage. En effet que ce passe-t-il quand nous créons une classe qui hérite d'une autre qui définie par exemple des propriétés paramétrées avec des attributs ?
Eh bien là aussi le framework nous permet de personnaliser le comportement de l'héritage des attributs.

 
Sélectionnez

/// <summary>
/// Classe définissant l'attribut personnalisé
/// </summary>
[AttributeUsage(AttributeTargets.Property, Inherited=true)]
public class DisplayAttribute : Attribute
{
    private bool display = false;

    /// <summary>
    /// Constructeur par défaut
    /// </summary>
    public DisplayAttribute(bool display)
    {
        this.display = display;
    }

    /// <summary>
    /// Obtient ou défini une valeur indiquant si la propriété suivi a été modifié
    /// </summary>
    public bool Display
    {
        get
        {
            return this.display;
        }
    }
}

Le paramètre nommé Inherited permet de définir si l'attribut peut affecter les membres hérités.
Exemple :

 
Sélectionnez

public class Information
{

	[Display(true)]
	public string Name
	{
		get
		{
			return this.name;
		}
		
		set
		{
			this.name = value;
		}
	}
}

public class InformationsSpecifiques : Information
{

}

Dans cette exemple la classe InformationsSpecifiques hérite de la classe Information qui défini l'attribut Display à vrai pour la propriété Name. Que ce passe-t-il lorsqu'un objet de type InformationsSpécifique est examiné pour en extraire les attributs ? Dans notre cas la propriété Name définie par la classe Information va être examineé et l'attribut Display va être détecté car nous avons défini le paramètre Inherited à true.
Au niveau du code de la détection y a t-il un moyen d'obtenir les attributs dont la propriété Inherited à false ?
Contrairement à toute attente oui ... En effet le fait de paramétrer un attribut avec Inherited=false, n'empèche pas les "inspecteurs" d'obtenir la valeur de l'attribut avec le code suivant :

 
Sélectionnez

pi.GetCustomAttributes(typeof(DisplayAttribute), true);

En effet le fait de positionner le second argument de GetCustumAttributes (inherited) à "vrai" permet d'obtenir les attributs hérités.

III-C. Instance multiple des attributs

Une autre question qui se pose est : "Est-il possible d'avoir plusieurs fois le même attribut sur le même élément ?".
Là encore la réponse nous est donnée par un paramètre nommé : AllowMultiple. Si ce paramètre est défini à true vous pourrez mettre deux fois l'attribut, sinon non.

 
Sélectionnez

public class Information
{

	[Author("dev01")]
	[Author("author")]
	public string Name
	{
		get
		{
			return this.name;
		}
		
		set
		{
			this.name = value;
		}
	}
}

IV. Cas concret d'utilisation des attributs personnalisés

Tout ceci est un peu trop théorique. C'est pourquoi nous allons voir un exemple d'utilisation des attributs personnalisés à travers un système permettant de paramétrer l'affichage des propriétés.

IV-A. La classe à paramétrer

La classe ci-dessous sera la classe dont nous allons paramétrer l'affichage.

 
Sélectionnez

public class Informations
{
   private string name;
   private string firstName;
   private string mail;
   
   public Informations()
   {
   
   }
   
   public string Name
   {
   		get
   		{
   			return this.name;
   		}
   		
   		set
   		{
   			this.name = value;
   		}
   }
}

IV-B. La classe d'attribut personnalisé

Cette classe défini notre attribut qui nous permettra de savoir si les informations de la classe doivent être visible ou non.

 
Sélectionnez

[AttributeUsage(AttributeTargets.Property, Inherited=true, AllowMultiple = false)]
public class DisplayAttribute : Attribute
{
	private bool display;
	
	public DisplayAttribute(bool display)
	{
		this.display = display;
	}
	
	public bool Display
	{
		get
		{
			return this.display;
		}
		
		set
		{
			this.display = value;
		}
	}
}

L'attribut que nous avons défini prend un paramètre dans le constructeur afin de définir si la propriété doit être affichée ou non.
La propriété qui nous interesse ici est Display.

IV-C. Utilisation de notre attribut personnalisé

Voyons maintenant comment nous allons nous servir de notre attribut.

 
Sélectionnez

public class Informations
{
   private string name;
   private string firstName;
   private string mail;
   
   public Informations()
   {
   
   }
   
   [Display(true)]
   public string Name
   {
   		get
   		{
   			return this.name;
   		}
   		
   		set
   		{
   			this.
   			this.name = value;
   		}
   }
   
   [Display(true)]
   public string FirstName
   {
   		get
   		{
   			return this.firstName;
   		}
   		
   		set
   		{
   			this.firstName = value;
   		}
   }
   
   public string Mail
   {
   		get
   		{
   			return this.mail;
   		}
   		
   		set
   		{
   			this.mail = value;
   		}
   }
   
}

L'utilisation de notre attribut dans la classe à paramétrer est simple.
Il nous suffit de le définir à true pour dire que nous voulons que la propriété soit affichée.

IV-D. La classe de gestion de l'affichage des propriétés

Cette classe permet d'afficher ou non une propriété en fonction de l'attribut Display.

 
Sélectionnez

private void UpdateInformations()
        {
            this.listViewInformations.Clear();
            this.listViewInformations.Columns.Clear();
            
            if( this.informations != null )
            {
                PropertyInfo[] pis = this.informations.GetType().GetProperties();
                foreach (PropertyInfo pi in pis)
                {
                    foreach (object o in pi.GetCustomAttributes(typeof(DisplayAttribute), false))
                    {
                        if (((DisplayAttribute)o).Display)
                        {
                            this.listViewInformations.Columns.Add(pi.Name);
                        }
                    }
                }

                List<string> val = new List<string>();
                for (int i = 0; i < this.listViewInformations.Columns.Count; i++)
                {
                    val.Add(this.informations.GetType().GetProperty(
						this.listViewInformations.Columns[i].Text).GetGetMethod().Invoke(this.informations, null).ToString()
						);   
                }
                this.listViewInformations.Items.Add(new ListViewItem(val.ToArray()));
            }
        }

Comme vous le voyez l'utilisation des attributs s'appuie beaucoup sur la réflexion.
Dans le détail cette fonction obtient la totalité des propriétés de la classe, et extrait pour chaque propriété la liste des attributs de type DisplayAttribute.
Ensuite si la propriété doit être affiché alors le nom de la propriété est ajouter comme colonne dans le ListView.
La suite est assez simple, il s'agit de remplir la ligne avec les informations.

V. Conclusion

L'utilisation des attributs personnalisés est très utile afin de paramétrer une classe au moment du développement pour influencer le comportement de composant utilisant cette classe.
C'est un moyen simple et efficace de fournir des informations sur la façon d'utiliser une classe.

VI. Téléchargement

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Copyright © 2006 Lainé Vincent. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.