¿Cómo obtener una lista de propiedades con un atributo dado?


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í:

[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 candente.

Author: abatishchev, 2010-02-17

7 answers

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

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

 330
Author: Marc Gravell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-02-17 16:09:52

La solución que más uso se basa en la respuesta de Tomas Petricek. Normalmente quiero hacer algo con ambos 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};
 39
Author: wsanville,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-09 17:38:52

Por lo que sé, no hay mejor manera en términos de trabajar con la biblioteca de reflexión de una manera más inteligente. Sin embargo, puedes usar 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 le ayuda a estructurar el código de una manera más legible.

 31
Author: Tomas Petricek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-18 21:35:57

Siempre hay LINQ:

t.GetProperties().Where(
    p=>p.GetCustomAttributes(typeof(MyAttribute), true).Length != 0)
 13
Author: P Daddy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-02-17 15:43:10

Si usted trata regularmente con Atributos en la Reflexión, es muy, muy práctico definir algunos métodos de extensión. Usted verá que en muchos proyectos por ahí. Este de aquí es uno que tengo a menudo:

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

Que puedes usar como typeof(Foo).HasAttribute<BarAttribute>();

Otros proyectos (por ejemplo StructureMap) tienen clases ReflectionHelper completas que usan árboles de expresión para tener una sintaxis fina para identificar, por ejemplo PropertyInfos. El uso entonces se ve así:

ReflectionHelper.GetProperty<Foo>(x => x.MyProperty).HasAttribute<BarAttribute>()
 5
Author: flq,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-02-17 16:00:56

Además de las respuestas anteriores: es mejor usar el método Any() en lugar de verificar la longitud de la colección:

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

El ejemplo en dotnetfiddle: https://dotnetfiddle.net/96mKep

 1
Author: feeeper,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-05 09:58:21

El mejor camino:

//if (attributes.Length == 1)
if (attributes.Length != 0)
 -4
Author: Behrooz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-24 14:22:24