Come creare attributi consentiti duplicati


96

Sto usando un attributo personalizzato ereditato da una classe di attributi. Lo sto usando in questo modo:

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

}

Ma viene visualizzato l'errore "Attributo" MyCustomAttribute "duplicato".
Come posso creare un attributo consentito duplicato?

Risposte:


184

Attacca un AttributeUsageattributo alla tua classe Attribute (sì, è boccone) e imposta AllowMultiplesu true:

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

6
Solo curioso: perché una classe "sigillata"?
Tomas Aschan

18
Microsoft consiglia di sigillare le classi di attributi quando possibile: msdn.microsoft.com/en-us/library/2ab31zeh.aspx
Anton Gogolev,

3
Perché sigillato? In breve: rende la ricerca degli attributi più veloce e non ha altro impatto.
Noel Widmer

Tranne che impedisce a chiunque altro di riutilizzare il tuo codice. Vale la pena notare che gli attributi di convalida in DataAnnotations non sono sigillati, il che è estremamente utile in quanto consente di creare specializzazioni degli stessi.
Neutrino

@Neutrino sealed dovrebbe essere usato ogni volta che non ti aspetti o non progetti che le tue classi vengano ereditate. Inoltre, quando l'ereditarietà può diventare la fonte di bug es: implementazioni thread-safe.
Francisco Neto

20

AttributeUsageAttribute ;-p

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

Notare, tuttavia, che se si utilizza ComponentModel ( TypeDescriptor), supporta solo un'istanza di attributo (per tipo di attributo) per membro; la riflessione grezza supporta qualsiasi numero ...


13

La soluzione di Anton è corretta, ma c'è un altro trucco .

In breve, a meno che il tuo attribbiute personalizzato non sovrascriva TypeId, accedervi attraverso PropertyDescriptor.GetCustomAttributes()restituirà solo una singola istanza del tuo attributo.


Ma funziona tramite: var customAtt = propertyInfo.GetCustomAttributes <MyCustomAttribute> ();
oo_dev

8

Per impostazione predefinita, i messaggi di posta Attributeelettronica sono limitati ad essere applicati una sola volta a un singolo campo / proprietà / ecc. Puoi vederlo dalla definizione della Attributeclasse su MSDN :

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

Pertanto, come altri hanno notato, tutte le sottoclassi sono limitate allo stesso modo e se si richiedono più istanze dello stesso attributo, è necessario impostare esplicitamente AllowMultiplesu true:

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

Sugli attributi che consentono utilizzi multipli, dovresti anche sovrascrivere la TypeIdproprietà per assicurarti che proprietà come PropertyDescriptor.Attributes funzionino come previsto. Il modo più semplice per farlo è implementare quella proprietà per restituire l'istanza dell'attributo stessa:

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

(Pubblicare questa risposta non perché gli altri abbiano torto, ma perché questa è una risposta più completa / canonica.)


3

In alternativa, pensa a riprogettare il tuo attributo per consentire una sequenza.

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

o

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

quindi analizza i valori per configurare il tuo attributo.

Per un esempio, controlla AuthorizeAttribute nel codice sorgente ASP.NET MVC su www.codeplex.com/aspnet .


3
È anche possibile che il MyCustomAttributecostruttore prenda un array di stringhe, a string[], con o senza il paramsmodificatore. Quindi potrebbe essere applicato con la sintassi [MyCustom("CONTROL", "ALT", "SHIFT", "D")](con params).
Jeppe Stig Nielsen

2

Dopo aver aggiunto AttributeUsage, assicurati di aggiungere questa proprietà alla tua classe Attribute

public override object TypeId
{
  get
  {
    return this;
  }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.