So erstellen Sie doppelte zulässige Attribute

96

Ich verwende ein benutzerdefiniertes Attribut, das von einer Attributklasse geerbt wurde. Ich benutze es so:

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

}

Der Fehler "Duplicate 'MyCustomAttribute' attribute" wird jedoch angezeigt.
Wie kann ich ein doppeltes zulässiges Attribut erstellen?

ebattulga
quelle

Antworten:

184

AttributeUsageKleben Sie ein Attribut in Ihre Attributklasse (yep, das ist mundvoll) und setzen Sie AllowMultipleauf true:

[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public sealed class MyCustomAttribute: Attribute
Anton Gogolev
quelle
6
Nur neugierig - warum eine "versiegelte" Klasse?
Tomas Aschan
18
Microsoft empfiehlt, Attributklassen nach Möglichkeit zu versiegeln
Anton
3
Warum versiegelt? Kurz gesagt: Beschleunigt die Attributsuche und hat keine weiteren Auswirkungen.
Noel Widmer
Abgesehen davon, dass andere Personen Ihren Code nicht wiederverwenden können. Beachten Sie, dass Validierungsattribute in DataAnnotations nicht versiegelt sind. Dies ist äußerst nützlich, da hierdurch Spezialisierungen erstellt werden können.
Neutrino
@Neutrino Sealed sollte immer dann verwendet werden, wenn Sie nicht erwarten oder nicht entwerfen, dass Ihre Klassen vererbt werden. Plus, wenn die Vererbung die Quelle von Fehlern werden kann, z. B.: Thread-sichere Implementierungen.
Francisco Neto
20

AttributeUsageAttribute ;-p

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

Beachten Sie jedoch, dass bei Verwendung von ComponentModel ( TypeDescriptor) nur eine Attributinstanz (pro Attributtyp) pro Mitglied unterstützt wird. Rohreflexion unterstützt eine beliebige Anzahl ...

Marc Gravell
quelle
13

Antons Lösung ist richtig, aber es gibt noch einen anderen Fall .

Kurz gesagt, wenn Ihr benutzerdefiniertes Attribut TypeId nicht überschreibt, wird beim Zugriff über PropertyDescriptor.GetCustomAttributes()nur eine einzige Instanz Ihres Attributs zurückgegeben.

mcdrewski
quelle
Aber es funktioniert über: var customAtt = propertyInfo.GetCustomAttributes <MyCustomAttribute> ();
oo_dev
8

Standardmäßig dürfen Attributes nur einmal auf ein einzelnes Feld / eine Eigenschaft / etc. Angewendet werden. Sie können dies aus der Definition der AttributeKlasse in MSDN ersehen :

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

Daher ist , wie andere haben festgestellt, werden alle Unterklassen in der gleichen Art und Weise beschränkt, und es sollten Sie mehrere Instanzen des gleichen Attribut erfordern, müssen Sie explizit AllowMultipleauf true:

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

Bei Attributen, die mehrere Verwendungen zulassen, sollten Sie die TypeIdEigenschaft auch überschreiben, um sicherzustellen, dass Eigenschaften wie PropertyDescriptor.Attributes erwartet funktionieren. Der einfachste Weg, dies zu tun, besteht darin, diese Eigenschaft zu implementieren, um die Attributinstanz selbst zurückzugeben:

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

(Diese Antwort nicht veröffentlichen, weil die anderen falsch sind, sondern weil dies eine umfassendere / kanonischere Antwort ist.)

Ian Kemp
quelle
3

Denken Sie alternativ daran, Ihr Attribut neu zu gestalten, um eine Sequenz zu ermöglichen.

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

oder

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

Analysieren Sie dann die Werte, um Ihr Attribut zu konfigurieren.

Ein Beispiel hierfür finden Sie im AuthorizeAttribute im ASP.NET MVC-Quellcode unter www.codeplex.com/aspnet .

Tvanfosson
quelle
3
Es ist sogar möglich, dass der MyCustomAttributeKonstruktor ein Array von Zeichenfolgen a string[]mit oder ohne paramsModifikator verwendet. Dann könnte es mit der Syntax [MyCustom("CONTROL", "ALT", "SHIFT", "D")](mit params) angewendet werden .
Jeppe Stig Nielsen
2

Stellen Sie nach dem Hinzufügen der AttributeUsage sicher, dass Sie diese Eigenschaft Ihrer Attribute-Klasse hinzufügen

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