Jak utworzyć zduplikowane dozwolone atrybuty

96

Używam atrybutu niestandardowego dziedziczonego z klasy atrybutów. Używam tego w ten sposób:

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

}

Ale wyświetlany jest błąd „Duplikat atrybutu„ MyCustomAttribute ””.
Jak mogę utworzyć zduplikowany dozwolony atrybut?

ebattulga
źródło

Odpowiedzi:

185

Przyklej AttributeUsageatrybut do swojej klasy atrybutu (tak, to jest kęs) i ustaw AllowMultiplena true:

[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public sealed class MyCustomAttribute: Attribute
Anton Gogolev
źródło
6
Po prostu ciekawy - dlaczego „zapieczętowane” zajęcia?
Tomas Aschan
18
Firma Microsoft zaleca uszczelnianie klas atrybutów, gdy tylko jest to możliwe: msdn.microsoft.com/en-us/library/2ab31zeh.aspx
Anton Gogolev
3
Dlaczego zapieczętowany? W skrócie: przyspiesza wyszukiwanie atrybutów i nie ma innego wpływu.
Noel Widmer
Tyle że powstrzymuje to innych przed ponownym użyciem Twojego kodu. Warto zaznaczyć, że atrybuty walidacyjne w DataAnnotations nie są zapieczętowane, co jest niezwykle przydatne, ponieważ umożliwia tworzenie ich specjalizacji.
Neutrino
@Neutrino Seal należy używać zawsze, gdy nie spodziewasz się lub nie planujesz dziedziczenia swoich klas. Dodatkowo, gdy dziedziczenie może stać się źródłem błędów, np .: implementacje bezpieczne dla wątków.
Francisco Neto
20

AttributeUsageAttribute ;-p

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

Należy jednak pamiętać, że jeśli używasz ComponentModel ( TypeDescriptor), obsługuje on tylko jedną instancję atrybutu (na typ atrybutu) na członka; surowe odbicie obsługuje dowolną liczbę ...

Marc Gravell
źródło
13

Rozwiązanie Antona jest poprawne, ale jest jeszcze jeden problem .

Krótko mówiąc, jeśli atrybut niestandardowy nie zastępuje TypeId, dostęp do niego za pośrednictwem PropertyDescriptor.GetCustomAttributes()zwróci tylko jedno wystąpienie atrybutu.

mcdrewski
źródło
Ale działa poprzez: var customAtt = propertyInfo.GetCustomAttributes <MyCustomAttribute> ();
oo_dev
9

Domyślnie Attributes są ograniczone do jednorazowego zastosowania do pojedynczego pola / właściwości / itp. Możesz to zobaczyć z definicji Attributeklasy w MSDN :

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

Dlatego, jak zauważyli inni, wszystkie podklasy są ograniczone w ten sam sposób i jeśli potrzebujesz wielu wystąpień tego samego atrybutu, musisz jawnie ustawić AllowMultiplena true:

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

W przypadku atrybutów, które umożliwiają wielokrotne użycie, należy również zastąpić TypeIdwłaściwość, aby upewnić się, że właściwości, takie jak właściwości, PropertyDescriptor.Attributes działają zgodnie z oczekiwaniami. Najłatwiejszym sposobem jest zaimplementowanie tej właściwości w celu zwrócenia samej instancji atrybutu:

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

(Publikowanie tej odpowiedzi nie jest spowodowane tym, że inni się mylą, ale dlatego, że jest to bardziej kompleksowa / kanoniczna odpowiedź).

Ian Kemp
źródło
3

Alternatywnie zastanów się nad przeprojektowaniem atrybutu, aby umożliwić sekwencję.

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

lub

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

następnie przeanalizuj wartości, aby skonfigurować atrybut.

Na przykład sprawdź AuthorizeAttribute w kodzie źródłowym ASP.NET MVC pod adresem www.codeplex.com/aspnet .

tvanfosson
źródło
3
Możliwe jest nawet, aby MyCustomAttributekonstruktor pobierał tablicę łańcuchów, a string[], z paramsmodyfikatorem lub bez niego . Następnie można go zastosować za pomocą składni [MyCustom("CONTROL", "ALT", "SHIFT", "D")](z params).
Jeppe Stig Nielsen
2

Po dodaniu AttributeUsage upewnij się, że dodajesz tę właściwość do swojej klasy Attribute

public override object TypeId
{
  get
  {
    return this;
  }
}

źródło