Cómo crear atributos permitidos duplicados


96

Estoy usando un atributo personalizado heredado de una clase de atributo. Lo estoy usando así:

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

}

Pero se muestra el error "Duplicar atributo 'MyCustomAttribute'".
¿Cómo puedo crear un atributo permitido duplicado?

Respuestas:


184

Pegue un AttributeUsageatributo en su clase de atributo (sí, eso es un bocado) y configúrelo AllowMultipleen true:

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

6
Solo curiosidad, ¿por qué una clase "sellada"?
Tomas Aschan

18
Microsoft recomienda sellar las clases de atributos siempre que sea posible: msdn.microsoft.com/en-us/library/2ab31zeh.aspx
Anton Gogolev

3
¿Por qué sellado? En resumen: hace que la búsqueda de atributos sea más rápida y no tiene ningún otro impacto.
Noel Widmer

Excepto que evita que cualquier otra persona reutilice su código. Cabe destacar que los atributos de validación en DataAnnotations no están sellados, lo cual es extremadamente útil ya que permite crear especializaciones de ellos.
Neutrino

@Neutrino sellado debe usarse siempre que no espere o no diseñe sus clases para que sean heredadas. Además, cuando la herencia puede convertirse en la fuente de errores, por ejemplo: implementaciones seguras para subprocesos.
Francisco Neto

20

AttributeUsageAttribute ;-p

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

Sin embargo, tenga en cuenta que si está utilizando ComponentModel ( TypeDescriptor), solo admite una instancia de atributo (por tipo de atributo) por miembro; la reflexión cruda admite cualquier número ...


13

La solución de Anton es correcta, pero hay otro problema .

En resumen, a menos que su atributo personalizado anule TypeId, acceder a él a través de PropertyDescriptor.GetCustomAttributes()solo devolverá una única instancia de su atributo.


Pero funciona a través de: var customAtt = propertyInfo.GetCustomAttributes <MyCustomAttribute> ();
oo_dev

8

De forma predeterminada, Attributelos mensajes de correo electrónico están limitados a aplicarse solo una vez a un solo campo / propiedad / etc. Puede ver esto en la definición de la Attributeclase en MSDN :

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

Por lo tanto, como han señalado otros, todas las subclases están limitadas de la misma manera, y si necesita varias instancias del mismo atributo, debe establecer explícitamente AllowMultipleen true:

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

En los atributos que permiten múltiples usos, también debe anular la TypeIdpropiedad para asegurarse de que propiedades como PropertyDescriptor.Attributes funcionan como se espera. La forma más sencilla de hacer esto es implementar esa propiedad para devolver la instancia del atributo en sí:

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

(Publicar esta respuesta no porque los demás estén equivocados, sino porque es una respuesta más completa / canónica).


3

Como alternativa, piense en rediseñar su atributo para permitir una secuencia.

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

o

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

luego analice los valores para configurar su atributo.

Para obtener un ejemplo de esto, consulte AuthorizeAttribute en el código fuente de ASP.NET MVC en www.codeplex.com/aspnet .


3
Incluso es posible hacer que el MyCustomAttributeconstructor tome una matriz de cadenas, a string[], con o sin el paramsmodificador. Entonces podría aplicarse con la sintaxis [MyCustom("CONTROL", "ALT", "SHIFT", "D")](con params).
Jeppe Stig Nielsen

2

Después de agregar AttributeUsage, asegúrese de agregar esta propiedad a su clase Attribute

public override object TypeId
{
  get
  {
    return this;
  }
}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.