Quels sont les attributs dans .NET?

206

Que sont les attributs dans .NET, à quoi servent-ils et comment créer mes propres attributs?

Corey
la source

Réponses:

146

Métadonnées. Données sur vos objets / méthodes / propriétés.

Par exemple, je peux déclarer un attribut appelé: DisplayOrder afin que je puisse facilement contrôler dans quel ordre les propriétés doivent apparaître dans l'interface utilisateur. Je pourrais ensuite l'ajouter à une classe et écrire des composants GUI qui extraient les attributs et ordonnent les éléments d'interface utilisateur de manière appropriée.

public class DisplayWrapper
{
    private UnderlyingClass underlyingObject;

    public DisplayWrapper(UnderlyingClass u)
    {
        underlyingObject = u;
    }

    [DisplayOrder(1)]
    public int SomeInt
    {
        get
        {
            return underlyingObject .SomeInt;
        }
    }

    [DisplayOrder(2)]
    public DateTime SomeDate
    {
        get
        {
            return underlyingObject .SomeDate;
        }
    }
}

Assurant ainsi que SomeInt est toujours affiché avant SomeDate lorsque vous travaillez avec mes composants GUI personnalisés.

Cependant, vous les verrez le plus souvent utilisés en dehors de l'environnement de codage direct. Par exemple, le concepteur Windows les utilise largement pour savoir comment gérer les objets personnalisés. Utiliser le BrowsableAttribute comme ceci:

[Browsable(false)]
public SomeCustomType DontShowThisInTheDesigner
{
    get{/*do something*/}
}

Indique au concepteur de ne pas répertorier cela dans les propriétés disponibles dans la fenêtre Propriétés au moment du design par exemple.

Vous pouvez également les utiliser pour la génération de code, les opérations de précompilation (telles que Post-Sharp) ou les opérations d'exécution telles que Reflection.Emit. Par exemple, vous pouvez écrire un peu de code pour le profilage qui enveloppe de manière transparente chaque appel de votre code et le chronomètre. Vous pouvez "désactiver" le timing via un attribut que vous placez sur des méthodes particulières.

public void SomeProfilingMethod(MethodInfo targetMethod, object target, params object[] args)
{
    bool time = true;
    foreach (Attribute a in target.GetCustomAttributes())
    {
        if (a.GetType() is NoTimingAttribute)
        {
            time = false;
            break;
        }
    }
    if (time)
    {
        StopWatch stopWatch = new StopWatch();
        stopWatch.Start();
        targetMethod.Invoke(target, args);
        stopWatch.Stop();
        HandleTimingOutput(targetMethod, stopWatch.Duration);
    }
    else
    {
        targetMethod.Invoke(target, args);
    }
}

Les déclarer est facile, créez simplement une classe qui hérite d'Attribute.

public class DisplayOrderAttribute : Attribute
{
    private int order;

    public DisplayOrderAttribute(int order)
    {
        this.order = order;
    }

    public int Order
    {
        get { return order; }
    }
}

Et rappelez-vous que lorsque vous utilisez l'attribut, vous pouvez omettre le suffixe "attribut", le compilateur l'ajoutera pour vous.

REMARQUE: les attributs ne font rien par eux-mêmes - il doit y avoir un autre code qui les utilise. Parfois, ce code a été écrit pour vous, mais parfois vous devez l'écrire vous-même. Par exemple, le compilateur C # se soucie de certains frameworks et certains frameworks en utilisent certains (par exemple NUnit recherche [TestFixture] sur une classe et [Test] sur une méthode de test lors du chargement d'un assembly).
Ainsi, lorsque vous créez votre propre attribut personnalisé, sachez que cela n'affectera pas du tout le comportement de votre code. Vous devrez écrire l'autre partie qui vérifie les attributs (via la réflexion) et agir sur eux.

Quibblesome
la source
32
Pour ce que ça vaut, voici
wprl
1
Comment utiliseriez-vous votre "SomeProfilingMethod" comme attribut?
RayLoveless
@RayLoveless ce n'est pas un attribut, SomeProfilingMethod est le code d'instrumentation qui recherche des attributs de profilage. Plus précisément dans l'exemple, j'ai donné sa recherche d'un attribut "opt-out" (NoTimingAttribute) par opposition à un attribut "opt-in". L'idée est que cela chronomètre tout.
Quibblesome
@Quibblesome pourriez-vous ajouter quelque chose comme "Les attributs ne font rien par eux-mêmes - il doit y avoir un autre code pour les utiliser (le compilateur se soucie du couple, différents frameworks en utilisent). La simple création d'attribut n'affectera pas le comportement du code - vous devez écrire l'autre partie qui vérifie les attributs (via la réflexion) et agir sur eux ". (ou je peux le faire si vous êtes d'accord). Beaucoup de gens s'attendent à ce que les attributs fonctionnent comme par magie et aucune des réponses ici ne clarifie cela. (ou tout simplement un lien vers stackoverflow.com/questions/4879521/… qui le couvre)
Alexei Levenkov
uniquement si vous arrêtez d'utiliser Bing. Non. j / k J'utilise DuckDuckGo comme mon principal qui utilise principalement Bing iirc. :)
Quibblesome
36

Beaucoup de gens ont répondu mais personne ne l'a mentionné jusqu'à présent ...

Les attributs sont largement utilisés avec la réflexion. La réflexion est déjà assez lente.

Il est très utile de marquer vos attributs personnalisés comme étant des sealedclasses pour améliorer leurs performances d'exécution.

C'est aussi une bonne idée de considérer où il serait approprié d'utiliser place un tel attribut, et d'attribuer votre attribut (!) Pour l'indiquer via AttributeUsage. La liste des utilisations d'attributs disponibles peut vous surprendre:

  • Assemblée
  • Module
  • Classe
  • Struct
  • Enum
  • Constructeur
  • Méthode
  • Propriété
  • Champ
  • un événement
  • Interface
  • Paramètre
  • Déléguer
  • ReturnValue
  • GenericParameter
  • Tout

Il est également cool que l'attribut AttributeUsage fasse partie de la signature de l'attribut AttributeUsage. Whoa pour les dépendances circulaires!

[AttributeUsageAttribute(AttributeTargets.Class, Inherited = true)]
public sealed class AttributeUsageAttribute : Attribute
Drew Noakes
la source
13

Les attributs sont une sorte de métadonnées pour les classes de marquage. Ceci est souvent utilisé dans WinForms par exemple pour masquer les contrôles de la barre d'outils, mais peut être implémenté dans votre propre application pour permettre aux instances de différentes classes de se comporter de manière spécifique.

Commencez par créer un attribut:

[AttributeUsage(AttributeTargets.Class, AllowMultiple=false, Inherited=true)]
public class SortOrderAttribute : Attribute
{
    public int SortOrder { get; set; }

    public SortOrderAttribute(int sortOrder)
    {
        this.SortOrder = sortOrder;
    }
}

Toutes les classes d'attributs doivent avoir le suffixe "Attribut" pour être valides.
Après cela, créez une classe qui utilise l'attribut.

[SortOrder(23)]
public class MyClass
{
    public MyClass()
    {
    }
}

Vous pouvez maintenant vérifier une classe spécifique ' SortOrderAttribute(si elle en a une) en procédant comme suit:

public class MyInvestigatorClass
{
    public void InvestigateTheAttribute()
    {
        // Get the type object for the class that is using
        // the attribute.
        Type type = typeof(MyClass);

        // Get all custom attributes for the type.
        object[] attributes = type.GetCustomAttributes(
            typeof(SortOrderAttribute), true);

        // Now let's make sure that we got at least one attribute.
        if (attributes != null && attributes.Length > 0)
        {
            // Get the first attribute in the list of custom attributes
            // that is of the type "SortOrderAttribute". This should only
            // be one since we said "AllowMultiple=false".
            SortOrderAttribute attribute = 
                attributes[0] as SortOrderAttribute;

            // Now we can get the sort order for the class "MyClass".
            int sortOrder = attribute.SortOrder;
        }
    }
}

Si vous voulez en savoir plus à ce sujet, vous pouvez toujours consulter MSDN qui a une assez bonne description.
J'espère que cela vous a aidé!

Patrik Svensson
la source
5

Un attribut est une classe qui contient des fonctionnalités que vous pouvez appliquer aux objets de votre code. Pour en créer une, créez une classe qui hérite de System.Attribute.

Quant à ce à quoi ils sont bons ... il y a des utilisations presque illimitées pour eux.

http://www.codeproject.com/KB/cs/dotnetattributes.aspx

Le Schtroumpf
la source
1
«fonctionnalité» n'est pas le bon mot ici; ce sont des métadonnées, pas des fonctionnalités
Marc Gravell
5

Les attributs sont comme des métadonnées appliquées à des classes, des méthodes ou des assemblys.

Ils sont bons pour un certain nombre de choses (visualisation du débogueur, marquage des choses comme obsolètes, marquage des choses comme sérialisables, la liste est infinie).

Il est facile de créer vos propres modèles personnalisés. Commencer ici:

http://msdn.microsoft.com/en-us/library/sw480ze8(VS.71).aspx

Stu
la source
5

Dans le projet sur lequel je travaille actuellement, il y a un ensemble d'objets d'interface utilisateur de différentes saveurs et un éditeur pour assembler ces objets pour créer des pages à utiliser dans l'application principale, un peu comme le concepteur de formulaires dans DevStudio. Ces objets existent dans leur propre assemblage et chaque objet est une classe dérivée de UserControlet possède un attribut personnalisé. Cet attribut est défini comme ceci:

[AttributeUsage (AttributeTargets::Class)]
public ref class ControlDescriptionAttribute : Attribute
{
public:
  ControlDescriptionAttribute (String ^name, String ^description) :
    _name (name),
    _description (description)
  {
  }

  property String ^Name
  {
    String ^get () { return _name; }
  }

  property String ^Description
  {
    String ^get () { return _description; }
  }

private:
  String
    ^ _name,
    ^ _description;
};

et je l'applique à une classe comme celle-ci:

[ControlDescription ("Pie Chart", "Displays a pie chart")]
public ref class PieControl sealed : UserControl
{
  // stuff
};

c'est ce que les affiches précédentes ont dit.

Pour utiliser l'attribut, l'éditeur a un Generic::List <Type>contenant les types de contrôle. Il existe une zone de liste à partir de laquelle l'utilisateur peut faire glisser et déposer sur la page pour créer une instance du contrôle. Pour remplir la zone de liste, j'obtiens le ControlDescriptionAttributecontrôle et remplis une entrée dans la liste:

// done for each control type
array <Object ^>
  // get all the custom attributes
  ^attributes = controltype->GetCustomAttributes (true);

Type
  // this is the one we're interested in
  ^attributetype = ECMMainPageDisplay::ControlDescriptionAttribute::typeid;

// iterate over the custom attributes
for each (Object ^attribute in attributes)
{
  if (attributetype->IsInstanceOfType (attribute))
  {
    ECMMainPageDisplay::ControlDescriptionAttribute
      ^description = safe_cast <ECMMainPageDisplay::ControlDescriptionAttribute ^> (attribute);

    // get the name and description and create an entry in the list
    ListViewItem
      ^item = gcnew ListViewItem (description->Name);

    item->Tag = controltype->Name;
    item->SubItems->Add (description->Description);

    mcontrols->Items->Add (item);
    break;
  }
}

Remarque: ce qui précède est C ++ / CLI mais ce n'est pas difficile à convertir en C # (ouais, je sais, C ++ / CLI est une abomination mais c'est avec cela que je dois travailler :-()

Vous pouvez mettre des attributs sur la plupart des choses et il existe toute une gamme d'attributs prédéfinis. L'éditeur mentionné ci-dessus recherche également des attributs personnalisés sur les propriétés qui décrivent la propriété et comment la modifier.

Une fois que vous aurez compris l'idée, vous vous demanderez comment vous avez pu vivre sans eux.

Skizz
la source
4

Comme dit précédemment, les attributs sont relativement faciles à créer. L'autre partie du travail consiste à créer du code qui l'utilise. Dans la plupart des cas, vous utiliserez la réflexion lors de l'exécution pour modifier le comportement en fonction de la présence d'un attribut ou de ses propriétés. Il existe également des scénarios dans lesquels vous inspecterez les attributs du code compilé pour effectuer une sorte d'analyse statique. Par exemple, les paramètres peuvent être marqués comme non nuls et l'outil d'analyse peut l'utiliser comme indice.

L'utilisation des attributs et la connaissance des scénarios appropriés pour leur utilisation constituent l'essentiel du travail.

denis phillips
la source
3

Les attributs sont, essentiellement, des bits de données que vous souhaitez associer à vos types (classes, méthodes, événements, énumérations, etc.)

L'idée est qu'au moment de l'exécution, un autre type / framework / outil interrogera votre type pour les informations dans l'attribut et agira en conséquence.

Ainsi, par exemple, Visual Studio peut interroger les attributs d'un contrôle tiers pour déterminer quelles propriétés du contrôle doivent apparaître dans le volet Propriétés au moment du design.

Les attributs peuvent également être utilisés dans la programmation orientée aspect pour injecter / manipuler des objets au moment de l'exécution en fonction des attributs qui les décorent et ajouter la validation, la journalisation, etc. aux objets sans affecter la logique métier de l'objet.

urini
la source
2

Pour commencer à créer un attribut, ouvrez un fichier source C #, tapez attributeet appuyez sur [TAB]. Il se développera en un modèle pour un nouvel attribut.

Jay Bazuzi
la source
6
Comment répond-il à la question? ce devrait être un commentaire, pas une réponse.
gdoron soutient Monica
1

Les attributs sont également couramment utilisés pour la programmation orientée aspect. Pour un exemple de cela, consultez le projet PostSharp .

Josh G
la source