Comment créer des attributs autorisés en double


96

J'utilise un attribut personnalisé hérité d'une classe d'attributs. Je l'utilise comme ceci:

[MyCustomAttribute("CONTROL")]
[MyCustomAttribute("ALT")]
[MyCustomAttribute("SHIFT")]
[MyCustomAttribute("D")]
public void setColor()
{

}

Mais l'erreur "Dupliquer l'attribut 'MyCustomAttribute'" s'affiche.
Comment puis-je créer un attribut autorisé en double?

Réponses:


184

Collez un AttributeUsageattribut sur votre classe d'attribut (oui, c'est une bouchée) et définissez-le AllowMultiplesur true:

[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public sealed class MyCustomAttribute: Attribute

6
Juste curieux - pourquoi une classe «scellée»?
Tomas Aschan

18
Microsoft recommande de sceller les classes d'attributs dans la mesure du possible: msdn.microsoft.com/en-us/library/2ab31zeh.aspx
Anton Gogolev

3
Pourquoi scellé? En bref: accélère la recherche d'attributs et n'a aucun autre impact.
Noel Widmer

Sauf que cela empêche quiconque de réutiliser votre code. A noter que les attributs de validation dans DataAnnotations ne sont pas scellés, ce qui est extrêmement utile car cela permet d'en créer des spécialisations.
Neutrino

@Neutrino scellé doit être utilisé chaque fois que vous ne vous attendez pas à ce que vos classes soient héritées ou que vous ne concevez pas. De plus, lorsque l'héritage peut devenir la source de bogues ex: implémentations thread-safe.
Francisco Neto

20

AttributeUsageAttribute ;-p

[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class MyAttribute : Attribute
{}

Notez, cependant, que si vous utilisez ComponentModel ( TypeDescriptor), il ne prend en charge qu'une seule instance d'attribut (par type d'attribut) par membre; la réflexion brute prend en charge n'importe quel nombre ...


13

La solution d'Anton est correcte, mais il y a un autre piège .

En bref, à moins que votre attrbiute personnalisé ne remplace TypeId, y accéder via PropertyDescriptor.GetCustomAttributes()ne renverra qu'une seule instance de votre attribut.


Mais cela fonctionne via: var customAtt = propertyInfo.GetCustomAttributes <MyCustomAttribute> ();
oo_dev

8

Par défaut, les Attributes sont limités à être appliqués une seule fois à un seul champ / propriété / etc. Vous pouvez le voir à partir de la définition de la Attributeclasse sur MSDN :

[AttributeUsageAttribute(..., AllowMultiple = false)]
public abstract class Attribute : _Attribute

Par conséquent, comme d'autres l'ont noté, toutes les sous-classes sont limitées de la même manière, et si vous avez besoin de plusieurs instances du même attribut, vous devez définir explicitement AllowMultiplesur true:

[AttributeUsage(..., AllowMultiple = true)]
public class MyCustomAttribute : Attribute

Sur les attributs qui autorisent plusieurs utilisations, vous devez également remplacer la TypeIdpropriété pour vous assurer que des propriétés telles que PropertyDescriptor.Attributes fonctionnent comme prévu. Le moyen le plus simple de le faire est d'implémenter cette propriété pour renvoyer l'instance d'attribut elle-même:

[AttributeUsage(..., AllowMultiple = true)]
public class MyCustomAttribute : Attribute
{
    public override object TypeId
    {
        get
        {
            return this;
        }
    }
}

(Publier cette réponse non pas parce que les autres ont tort, mais parce que c'est une réponse plus complète / canonique.)


3

Comme alternative, pensez à repenser votre attribut pour permettre une séquence.

[MyCustomAttribute(Sequence="CONTROL,ALT,SHIFT,D")]

ou

[MyCustomAttribute("CONTROL-ALT-SHIFT-D")]

puis analysez les valeurs pour configurer votre attribut.

Pour un exemple de cela, consultez le code source AuthorizeAttribute dans ASP.NET MVC à l' adresse www.codeplex.com/aspnet .


3
Il est même possible que le MyCustomAttributeconstructeur prenne un tableau de chaînes, a string[], avec ou sans le paramsmodificateur. Ensuite, il pourrait être appliqué avec la syntaxe [MyCustom("CONTROL", "ALT", "SHIFT", "D")](avec params).
Jeppe Stig Nielsen

2

Une fois que vous avez ajouté AttributeUsage, assurez-vous d'ajouter cette propriété à votre classe d'attribut

public override object TypeId
{
  get
  {
    return this;
  }
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.