Jak uzyskać listę właściwości z danym atrybutem?

Mam typ t i chciałbym uzyskać listę publicznych właściwości, które mają atrybut MyAttribute. Atrybut jest oznaczony AllowMultiple = false, tak:

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

Obecnie mam to, ale myślę, że jest lepszy sposób:

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

Jak mogę to poprawić? Przepraszam, jeśli to duplikat, jest tam mnóstwo wątków refleksji...wygląda na to, że to gorący temat.

Author: abatishchev, 2010-02-17

7 answers

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

Pozwala to uniknąć zmaterializowania jakichkolwiek instancji atrybutów (tzn. jest to tańsze niż 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/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-17 16:09:52

Rozwiązanie, z którego najczęściej korzystam, opiera się na odpowiedzi Tomasa Petricka. Zazwyczaj chcę zrobić coś z ZARÓWNO atrybutem jak i właściwością.

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/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-09 17:38:52

Z tego, co wiem, nie ma lepszego sposobu na mądrzejszą pracę z biblioteką Reflection. Możesz jednak użyć LINQ, aby uczynić kod nieco ładniejszym:

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'

Wierzę, że to pomaga uporządkować kod w bardziej czytelny sposób.

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-18 21:35:57

Zawsze jest 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/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-17 15:43:10

Jeśli masz do czynienia regularnie z atrybutami W Reflection, bardzo praktyczne jest zdefiniowanie niektórych metod rozszerzenia. Zobaczysz to w wielu projektach. Ten tutaj jest taki, który często mam:

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

Które możesz użyć jak typeof(Foo).HasAttribute<BarAttribute>();

Inne projekty (np. StructureMap) mają pełnowartościowe klasy ReflectionHelper, które używają drzew wyrażeń, aby mieć dokładną składnię do tożsamości, np. PropertyInfos. Użycie wtedy wygląda tak:

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/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-17 16:00:56

Oprócz poprzednich odpowiedzi: lepiej użyć metody Any() zamiast sprawdzić długość zbioru:

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

Przykład 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/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-05 09:58:21

The better way:

//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/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-24 14:22:24