2010-02-17 11 views
162

Tengo un tipo, t, y me gustaría obtener una lista de las propiedades públicas que tienen el atributo MyAttribute. El atributo está marcado con AllowMultiple = false, así:¿Cómo obtener una lista de propiedades con un atributo determinado?

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] 

Actualmente lo que tengo es esto, pero estoy pensando que hay una mejor manera:

foreach (PropertyInfo prop in t.GetProperties()) 
{ 
    object[] attributes = prop.GetCustomAttributes(typeof(MyAttribute), true); 
    if (attributes.Length == 1) 
    { 
     //Property with my custom attribute 
    } 
} 

¿Cómo puedo mejorar esto? Mis disculpas si esto es un duplicado, hay un montón de hilos de reflexión por ahí ... parece que es un tema bastante candente.

+0

Nop. Necesita un PropertyInfo antes de poder averiguar si la propiedad tiene un atributo. –

Respuesta

303
var props = t.GetProperties().Where(
       prop => Attribute.IsDefined(prop, typeof(MyAttribute))); 

Esto evita tener que materializar cualquier instancia de atributos (es decir, es más barato que GetCustomAttribute[s]()

+0

Buena sugerencia. Sin embargo, necesitaré la instancia de atributo, pero me gusta. – wsanville

+1

Estaba buscando una forma de verificar la existencia de un atributo sin el efecto secundario de que se llame a la propiedad. Gracias Marc, ¡funciona! –

+1

@ ÖrjanJämte no se llama a la propiedad 'get' incluso cuando se usa' GetCustomAttributes'; sin embargo, el atributo es * instanciado *, que no es gratis. Si no necesita verificar valores específicos del atributo, 'IsDefined' es más barato. Y en 4.5, hay formas de verificar los datos de instanciación * sin * realmente crear instancias de atributo (aunque esto es * previsto * solo para escenarios muy específicos) –

-3

la mejor manera:

//if (attributes.Length == 1) 
if (attributes.Length != 0) 
+0

El atributo en cuestión tiene AllowMultiple = false, por lo que hay 0 o 1. Debería haber especificado eso en mi pregunta. – wsanville

+0

voto a favor? ¿Por qué? + (15 caracteres) – Behrooz

+1

Dunno, no era yo. – wsanville

31

Por lo que yo sé, no hay ninguna manera mejor en términos de trabajar con la biblioteca de reflexión de una manera más inteligente. Sin embargo, se puede utilizar LINQ para hacer el código un poco más agradable:

var props = from p in t.GetProperties() 
      let attrs = p.GetCustomAttributes(typeof(MyAttribute), true) 
      where attrs.Length != 0 select p; 

// Do something with the properties in 'props' 

creo que esto ayuda a estructurar el código de una manera más fácil de leer.

12

Siempre hay LINQ:

t.GetProperties().Where(
    p=>p.GetCustomAttributes(typeof(MyAttribute), true).Length != 0) 
5

Si usted se ocupa regularmente con atributos en la reflexión, es muy, muy práctico para definir algunos métodos de extensión. Lo verás en muchos proyectos. Este de aquí es uno que a menudo tienen:

public static bool HasAttribute<T>(this ICustomAttributeProvider provider) where T : Attribute 
{ 
    var atts = provider.GetCustomAttributes(typeof(T), true); 
    return atts.Length > 0; 
} 

que se puede utilizar como typeof(Foo).HasAttribute<BarAttribute>();

Otros proyectos (por ejemplo StructureMap) tienen clases ReflectionHelper de pleno derecho los que utilizan los árboles de expresión para tener una multa de sintaxis a la identidad, por ejemplo, PropertyInfos. Uso entonces parece que:

ReflectionHelper.GetProperty<Foo>(x => x.MyProperty).HasAttribute<BarAttribute>() 
34

La solución que terminan usando más se basa apagado de la respuesta de Tomas Petricek. . Por lo general quiero hacer algo con tanto el atributo y la propiedad.

var props = from p in this.GetType().GetProperties() 
      let attr = p.GetCustomAttributes(typeof(MyAttribute), true) 
      where attr.Length == 1 
      select new { Property = p, Attribute = attr.First() as MyAttribute}; 
+0

+1 - "Por lo general, quiero hacer algo con el atributo y la propiedad" es lo que estaba buscando, muchas gracias por publicar tu respuesta. –

0

Además de comprobar la validez vious respuestas: Es mejor utilizar el método Any() en lugar de la longitud de verificación de la colección:

propertiesWithMyAttribute = type.GetProperties() 
    .Where(x => x.GetCustomAttributes(typeof(MyAttribute), true).Any()); 
Cuestiones relacionadas