web-dev-qa-db-fra.com

Comment créer un attribut personnalisé en C #

J'ai essayé de nombreuses fois mais je ne suis toujours pas en mesure de comprendre l'utilisation d'attributs personnalisés (j'ai déjà parcouru de nombreux liens).

Quelqu'un peut-il m'expliquer s'il vous plaît un exemple très basique d'un attribut personnalisé avec code?

109
slash shogdhe

Bien que le code permettant de créer une personnalisation Attribut soit relativement simple, il est très important que vous compreniez quels sont les attributs:

Les attributs sont des métadonnées compilées dans votre programme. Les attributs eux-mêmes n’ajoutent aucune fonctionnalité à une classe, une propriété ou un module, mais simplement des données. Cependant, en utilisant la réflexion, on peut exploiter ces attributs pour créer des fonctionnalités.

Ainsi, par exemple, regardons Bloc d'application de validation , à partir de Bibliothèque d'entreprise . Si vous regardez un exemple de code, vous verrez:

    /// <summary>
    /// blah blah code.
    /// </summary>
    [DataMember]
    [StringLengthValidator(8, RangeBoundaryType.Inclusive, 8, RangeBoundaryType.Inclusive, MessageTemplate = "\"{1}\" must always have \"{4}\" characters.")]
    public string Code { get; set; }

À partir de l'extrait ci-dessus, on peut supposer que le code sera toujours validé, à chaque modification, conformément aux règles du validateur (dans l'exemple, il doit comporter au moins 8 caractères et au plus 8 caractères). Mais la vérité est que l'attribut ne fait rien, il ajoute seulement des métadonnées à la propriété.

Cependant, la bibliothèque d'entreprise a un Validation.Validate méthode qui examinera votre objet et vérifiera, pour chaque propriété, si le contenu enfreint la règle informée par l'attribut.

Voilà comment vous devriez penser aux attributs - un moyen d’ajouter à votre code des données qui pourraient être utilisées ultérieurement par d’autres méthodes/classes/etc.

91
Bruno Brant

Vous commencez par écrire une classe qui dérive de Attribute :

public class MyCustomAttribute: Attribute
{
    public string SomeProperty { get; set; }
}

Ensuite, vous pouvez décorer n'importe quoi (classe, méthode, propriété, ...) avec cet attribut:

[MyCustomAttribute(SomeProperty = "foo bar")]
public class Foo
{

}

et finalement vous utiliseriez la réflexion pour le récupérer:

var customAttributes = (MyCustomAttribute[])typeof(Foo).GetCustomAttributes(typeof(MyCustomAttribute), true);
if (customAttributes.Length > 0)
{
    var myAttribute = customAttributes[0];
    string value = myAttribute.SomeProperty;
    // TODO: Do something with the value
}

Vous pouvez limiter les types de cibles auxquels cet attribut personnalisé pourrait être appliqué à l'aide de l'attribut AttributeUsage :

/// <summary>
/// This attribute can only be applied to classes
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class MyCustomAttribute : Attribute

Ce qu'il faut savoir sur les attributs:

  • Les attributs sont des métadonnées.
  • Ils sont cuits dans l’Assemblée à au moment de la compilation , ce qui a de très graves conséquences sur la manière dont vous pourriez définir leurs propriétés. Seules les valeurs constantes (connues à la compilation) sont acceptées
  • La seule façon de donner un sens et d'utiliser des attributs personnalisés est d'utiliser Reflection . Ainsi, si vous n'utilisez pas la réflexion au moment de l'exécution pour les récupérer et décorer quelque chose avec un attribut personnalisé, n'attendez pas grand-chose.
  • Le temps de création des attributs est non déterministe. Ils sont instanciés par le CLR et vous n’avez absolument aucun contrôle sur celui-ci.
250
Darin Dimitrov

Utiliser/Copier grande réponse de Darin Dimitrov , voici comment accéder à un attribut personnalisé sur une propriété et non à une classe:

La propriété décorée [de classe Foo]:

[MyCustomAttribute(SomeProperty = "This is a custom property")]
public string MyProperty { get; set; }

Aller le chercher:

PropertyInfo propertyInfo = typeof(Foo).GetProperty(propertyToCheck);
object[] attribute = propertyInfo.GetCustomAttributes(typeof(MyCustomAttribute), true);
if (attribute.Length > 0)
{
    MyCustomAttribute myAttribute = (MyCustomAttribute)attribute[0];
    string propertyValue = myAttribute.SomeProperty;
}

Vous pouvez lancer ceci dans une boucle et utiliser réflexion pour accéder à cet attribut personnalisé sur chaque propriété de la classe Foo, ainsi:

foreach (PropertyInfo propertyInfo in Foo.GetType().GetProperties())
{
    string propertyName = propertyInfo.Name;

    object[] attribute = propertyInfo.GetCustomAttributes(typeof(MyCustomAttribute), true);
    // Just in case you have a property without this annotation
    if (attribute.Length > 0)
    {
        MyCustomAttribute myAttribute = (MyCustomAttribute)attribute[0];
        string propertyValue = myAttribute.SomeProperty;
        // TODO: whatever you need with this propertyValue
    }
}

Major merci à vous, Darin !!

20
Hopper