Share via


Écriture des attributs personnalisés

Pour concevoir vos propres attributs personnalisés, vous n'avez pas besoin de maîtriser beaucoup de nouveaux concepts. Si vous avez l'habitude de la programmation orientée objet et savez concevoir des classes, vous avez déjà la majorité des connaissances nécessaires. Les attributs personnalisés sont essentiellement des classes traditionnelles qui dérivent directement ou indirectement de System.Attribute. Tout comme les classes traditionnelles, les attributs personnalisés contiennent des méthodes qui enregistrent et récupèrent les données.

Les premières étapes permettant de concevoir correctement des classes d'attributs personnalisées sont les suivantes :

  • Application de AttributeUsageAttribute

  • Déclaration de la classe d'attributs

  • Déclaration des constructeurs

  • Déclaration des propriétés

Cette section décrit chacune de ces étapes et conclut par un exemple d'attribut personnalisé.

Application de AttributeUsageAttribute

Une déclaration attribute personnalisée commence par le AttributeUsageAttribute, qui définit certaines des caractéristiques clés de votre classe d'attributs. Par exemple, vous pouvez spécifier si d'autres classes peuvent hériter de votre attribut ou indiquer les éléments auxquels l'attribut peut être appliqué. Le fragment de code suivant illustre comment utiliser le AttributeUsageAttribute.

<AttributeUsage(AttributeTargets.All, Inherited := False, AllowMultiple := True)>
Public Class SomeClass
    Inherits Attribute
    '...
End Class
[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
[AttributeUsage(AttributeTargets::All, Inherited = false, AllowMultiple = true)]

System.AttributeUsageAttribute a trois membres qui sont importants pour la création des attributs personnalisés : AttributeTargets, Inherited et AllowMultiple.

AttributeTargets, membre

Dans l'exemple précédent, AttributeTargets.Allest spécifié, indiquant que cet attribut peut être appliqué à tous les éléments du programme. Vous pouvez également spécifier AttributeTargets.Class, indiquant que votre attribut ne peut être appliqué qu'à une classe ou AttributeTargets.Method, indiquant que votre attribut ne peut être appliqué qu'à une méthode. Tous les éléments du programme peuvent être, de cette manière, marqués pour description par un attribut personnalisé.

Vous pouvez également passer plusieurs instances de AttributeTargets. Le fragment de code suivant spécifie qu'un attribut personnalisé peut être appliqué à n'importe quelle classe ou méthode.

<AttributeUsage(AttributeTargets.Class Or AttributeTargets.Method)>
Public Class SomeOtherClass
    Inherits Attribute
    '...
End Class
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
[AttributeUsage(AttributeTargets::Class | AttributeTargets::Method)]

Inherited, propriété

La propriété Inherited indique si les classes dérivées de celles auxquelles votre attribut s'applique peuvent hériter de votre attribut. Cette propriété accepte un indicateur true (valeur par défaut) ou false. Dans l'exemple de code suivant, MyAttribute a une valeur Inherited true par défaut, tandis que YourAttribute a une valeur Inherited false.

' This defaults to Inherited = true.
Public Class MyAttribute
    Inherits Attribute
    '...
End Class

<AttributeUsage(AttributeTargets.Method, Inherited := False)>
Public Class YourAttribute
    Inherits Attribute
    '...
End Class
// This defaults to Inherited = true.
public class MyAttribute : Attribute
{
    //...
}

[AttributeUsage(AttributeTargets.Method, Inherited = false)]
public class YourAttribute : Attribute
{
    //...
}
// This defaults to Inherited = true.
public ref class MyAttribute : Attribute
{
    //...
};

[AttributeUsage(AttributeTargets::Method, Inherited = false)]
public ref class YourAttribute : Attribute
{
    //...
};

Les deux attributs sont alors appliqués à une méthode dans la classe de base MyClass.

Public Class MeClass
    <MyAttribute>
    <YourAttribute>
    Public Overridable Sub MyMethod()
        '...
    End Sub
End Class
public class MyClass
{
    [MyAttribute]
    [YourAttribute]
    public virtual void MyMethod()
    {
        //...
    }
}
public ref class MyClass
{
public:
    [MyAttribute]
    [YourAttribute]
    virtual void MyMethod()
    {
        //...
    }
};

Finalement, la classe YourClass est héritée de la classe de base MyClass. La méthode MyMethod indique MyAttribute, mais pas YourAttribute.

Public Class YourClass
    Inherits MeClass
    ' MyMethod will have MyAttribute but not YourAttribute.
    Public Overrides Sub MyMethod()
        '...
    End Sub

End Class
public class YourClass : MyClass
{
    // MyMethod will have MyAttribute but not YourAttribute.
    public override void MyMethod()
    {
        //...
    }

}
public ref class YourClass : MyClass
{
public:
    // MyMethod will have MyAttribute but not YourAttribute.
    virtual void MyMethod() override
    {
        //...
    }

};

AllowMultiple, propriété

La propriété AllowMultiple indique si plusieurs instances de votre attribut peuvent exister sur un élément. Si elle a la valeur true, plusieurs instances sont autorisées ; si elle a la valeur false (par défaut), une seule instance est autorisée.

Dans l'exemple de code suivant, MyAttribute a la valeur AllowMultiple false par défaut, tandis que YourAttribute a la valeur true.

' This defaults to AllowMultiple = false.
Public Class MyAttribute
    Inherits Attribute
End Class

<AttributeUsage(AttributeTargets.Method, AllowMultiple := true)>
Public Class YourAttribute
    Inherits Attribute
End Class
//This defaults to AllowMultiple = false.
public class MyAttribute : Attribute
{
}

[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class YourAttribute : Attribute
{
}
//This defaults to AllowMultiple = false.
public ref class MyAttribute : Attribute
{
};

[AttributeUsage(AttributeTargets::Method, AllowMultiple = true)]
public ref class YourAttribute : Attribute
{
};

Lorsque plusieurs instances de ces attributs sont appliquées, MyAttribute génère une erreur de compilateur. L'exemple de code suivant indique l'utilisation valide de YourAttribute et l'utilisation non valide de MyAttribute.

Public Class MyClass
    ' This produces an error.
    ' Duplicates are not allowed.
    <MyAttribute>
    <MyAttribute>
    Public Sub MyMethod()
        '...
    End Sub

    ' This is valid.
    <YourAttribute>
    <YourAttribute>
    Public Sub YourMethod()
        '...
    End Sub
End Class
public class MyClass
{
    // This produces an error.
    // Duplicates are not allowed.
    [MyAttribute]
    [MyAttribute]
    public void MyMethod()
    {
        //...
    }

    // This is valid.
    [YourAttribute]
    [YourAttribute]
    public void YourMethod()
    {
        //...
    }
}
public ref class MyClass
{
public:
    // This produces an error.
    // Duplicates are not allowed.
    [MyAttribute]
    [MyAttribute]
    void MyMethod()
    {
        //...
    }

    // This is valid.
    [YourAttribute]
    [YourAttribute]
    void YourMethod()
    {
        //...
    }
};

Si true est affecté aux deux propriétés AllowMultiple et Inherited, une classe héritée d'une autre peut hériter d'un attribut et avoir une autre instance du même attribut appliquée dans la même classe enfant. Si false est affecté à AllowMultiple, les valeurs des attributs de la classe parente seront écrasées par toute nouvelle instance du même attribut de la classe enfant.

Déclaration de la classe d'attributs

Après avoir appliqué AttributeUsageAttribute, vous pouvez commencer à définir les particularités de votre attribut. La déclaration d'une classe d'attributs ressemble à la déclaration d'une classe traditionnelle, comme cela est démontré par le code suivant.

<AttributeUsage(AttributeTargets.Method)>
Public Class MyAttribute
    Inherits Attribute
    ' . . .
End Class
[AttributeUsage(AttributeTargets.Method)]
public class MyAttribute : Attribute
{
    // . . .
}
[AttributeUsage(AttributeTargets::Method)]
public ref class MyAttribute : Attribute
{
    // . . .
};

Cette définition de l'attribut illustre les points suivants :

  • Les classes d'attributs doivent être déclarées comme des classes publiques.

  • Par convention, le nom de la classe d'attributs se termine par le mot Attribute. Bien qu'il ne soit pas obligatoire, le respect de cette convention est recommandé pour la lisibilité. Lorsque l'attribut est appliqué, l'inclusion du mot Attribute est optionnelle.

  • Toutes les classes d'attributs doivent hériter directement ou indirectement de System.Attribute.

  • Dans Microsoft Visual Basic, toutes les classes d'attributs personnalisés doivent avoir l'attribut AttributeUsageAttribute.

Déclaration des constructeurs

Les attributs sont initialisés avec les constructeurs de la même façon que les classes traditionnelles. Le fragment de code suivant illustre un constructeur d'attribut classique. Ce constructeur public accepte un paramètre et lui affecte une valeur égale à la variable membre.

Public Sub New(myvalue As Boolean)
    Me.myvalue = myvalue
End Sub
public MyAttribute(bool myvalue)
{
    this.myvalue = myvalue;
}
MyAttribute(bool myvalue)
{
    this->myvalue = myvalue;
}

Vous pouvez surcharger le constructeur afin d'accueillir les différentes combinaisons des valeurs. Si vous définissez également une propriété pour votre classe d'attributs personnalisés, vous pouvez utiliser une combinaison de paramètres nommés et positionnels lors de l'initialisation de l'attribut. Vous définissez généralement tous les paramètres obligatoires comme positionnels et tous les paramètres optionnels comme nommés. Dans ce cas, l'attribut ne peut pas être initialisé sans le paramètre obligatoire. Tous les autres paramètres sont optionnels. Notez qu'en Visual Basic, les constructeurs d'une classe d'attributs ne doivent pas utiliser d'argument ParamArray.

L'exemple de code suivant montre comment un attribut utilisant le constructeur précédent peut être appliqué à l'aide des paramètres obligatoires et optionnels. Il suppose que l'attribut a une valeur booléenne obligatoire et une propriété de type chaîne optionnelle.

' One required (positional) and one optional (named) parameter are applied.
<MyAttribute(false, OptionalParameter := "optional data")>
Public Class SomeClass
    '...
End Class

' One required (positional) parameter is applied.
<MyAttribute(false)>
Public Class SomeOtherClass
    '...
End Class
// One required (positional) and one optional (named) parameter are applied.
[MyAttribute(false, OptionalParameter = "optional data")]
public class SomeClass
{
    //...
}
// One required (positional) parameter is applied.
[MyAttribute(false)]
public class SomeOtherClass
{
    //...
}
// One required (positional) and one optional (named) parameter are applied.
[MyAttribute(false, OptionalParameter = "optional data")]
public ref class SomeClass
{
    //...
};
// One required (positional) parameter is applied.
[MyAttribute(false)]
public ref class SomeOtherClass
{
    //...
};

Déclaration des propriétés

Si vous souhaitez définir un paramètre nommé ou permettre le retour aisé des valeurs enregistrées par votre attribut, déclarez une propriété. Les propriétés d'attribut doivent être déclarées comme des entités publiques avec une description du type de données qui sera retourné. Définissez la variable qui contiendra la valeur de votre propriété et associez-la aux méthodes get et set. L'exemple de code suivant illustre comment implémenter une propriété simple dans votre attribut.

Public Property MyProperty As Boolean
    Get
       Return Me.myvalue
    End Get
    Set
        Me.myvalue = Value
    End Set
End Property
public bool MyProperty
{
    get {return this.myvalue;}
    set {this.myvalue = value;}
}
property bool MyProperty
{
    bool get() {return this->myvalue;}
    void set(bool value) {this->myvalue = value;}
}

Exemple d'attribut personnalisé

Cette section regroupe les informations précédentes et montre comment concevoir un attribut simple qui documente les informations concernant l'auteur d'une section de code. Dans cet exemple, l'attribut enregistre le nom et le niveau du programmateur et indique si le code a été révisé. Il utilise trois variables privées pour enregistrer les valeurs réelles à sauvegarder. Chaque variable est représentée par une propriété publique qui obtient et définit les valeurs. Finalement, le constructeur est défini avec deux paramètres obligatoires.

<AttributeUsage(AttributeTargets.All)>
Public Class DeveloperAttribute
    Inherits Attribute
    ' Private fields.
    Private myname As String
    Private mylevel As String
    Private myreviewed As Boolean

    ' This constructor defines two required parameters: name and level.

    Public Sub New(name As String, level As String)
        Me.myname = name
        Me.mylevel = level
        Me.myreviewed = False
    End Sub

    ' Define Name property.
    ' This is a read-only attribute.

    Public Overridable ReadOnly Property Name() As String
        Get
            Return myname
        End Get
    End Property

    ' Define Level property.
    ' This is a read-only attribute.

    Public Overridable ReadOnly Property Level() As String
        Get
            Return mylevel
        End Get
    End Property

    ' Define Reviewed property.
    ' This is a read/write attribute.

    Public Overridable Property Reviewed() As Boolean
        Get
            Return myreviewed
        End Get
        Set
            myreviewed = value
        End Set
    End Property
End Class
[AttributeUsage(AttributeTargets.All)]
public class DeveloperAttribute : Attribute
{
    // Private fields.
    private string name;
    private string level;
    private bool reviewed;

    // This constructor defines two required parameters: name and level.

    public DeveloperAttribute(string name, string level)
    {
        this.name = name;
        this.level = level;
        this.reviewed = false;
    }

    // Define Name property.
    // This is a read-only attribute.

    public virtual string Name
    {
        get {return name;}
    }

    // Define Level property.
    // This is a read-only attribute.

    public virtual string Level
    {
        get {return level;}
    }

    // Define Reviewed property.
    // This is a read/write attribute.

    public virtual bool Reviewed
    {
        get {return reviewed;}
        set {reviewed = value;}
    }
}
[AttributeUsage(AttributeTargets::All)]
public ref class DeveloperAttribute : Attribute
{
    // Private fields.
private:
    String^ name;
    String^ level;
    bool reviewed;

public:
    // This constructor defines two required parameters: name and level.

    DeveloperAttribute(String^ name, String^ level)
    {
        this->name = name;
        this->level = level;
        this->reviewed = false;
    }

    // Define Name property.
    // This is a read-only attribute.

    virtual property String^ Name
    {
        String^ get() {return name;}
    }

    // Define Level property.
    // This is a read-only attribute.

    virtual property String^ Level
    {
        String^ get() {return level;}
    }

    // Define Reviewed property.
    // This is a read/write attribute.

    virtual property bool Reviewed
    {
        bool get() {return reviewed;}
        void set(bool value) {reviewed = value;}
    }
};

Vous pouvez appliquer cet attribut à l'aide du nom complet, DeveloperAttribute, ou du nom abrégé, Developer, de l'une des manières suivantes.

<Developer("Joan Smith", "1")>

-or-

<Developer("Joan Smith", "1", Reviewed := true)>
[Developer("Joan Smith", "1")]

-or-

[Developer("Joan Smith", "1", Reviewed = true)]
[Developer("Joan Smith", "1")]

-or-

[Developer("Joan Smith", "1", Reviewed = true)]

Le premier exemple montre l'application de l'attribut avec seulement les paramètres nommés obligatoires, tandis que le deuxième exemple montre l'application de l'attribut avec les paramètres obligatoires et optionnels.

Voir aussi

Référence

System.Attribute

AttributeUsageAttribute

Concepts

Extension des métadonnées à l'aide des attributs