2010-02-17 10 views
162

J'ai un type, t, et je voudrais obtenir une liste des propriétés publiques qui ont l'attribut MyAttribute. L'attribut est marqué par AllowMultiple = false, comme ceci:Comment obtenir une liste de propriétés avec un attribut donné?

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

Actuellement ce que j'ai est, mais je pense qu'il ya une meilleure façon:

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

Comment puis-je améliorer cela? Mes excuses s'il s'agit d'un doublon, il y a une tonne de fils de réflexion là-bas ... semble que c'est un sujet brûlant.

+0

Nope. Vous avez besoin d'un PropertyInfo avant de savoir si la propriété a un attribut. –

Répondre

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

Cela évite d'avoir à se matérialiser toutes les instances d'attributs (il est moins cher que GetCustomAttribute[s]()

+0

Bonne suggestion. Je vais cependant avoir besoin de l'instance d'attribut, mais je l'aime bien. – wsanville

+1

Je cherchais juste un moyen de vérifier l'existence d'un attribut sans l'effet secondaire que la propriété obtient est appelée. Merci Marc, ça marche! –

+1

@ ÖrjanJämte la propriété 'get' n'est pas appelée même en utilisant' GetCustomAttributes'; cependant, l'attribut est * instancié *, ce qui n'est pas gratuit. Si vous n'avez pas besoin de vérifier les valeurs spécifiques de l'attribut, 'IsDefined' est moins cher. Et dans 4.5, il existe des moyens de vérifier les données d'instanciation * sans * créer réellement des instances d'attribut (bien que cela soit * destiné * pour des scénarios très spécifiques seulement) –

-3

la meilleure façon:

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

L'attribut en question a AllowMultiple = false, donc il y a 0 ou 1. J'aurais dû le préciser dans ma question. – wsanville

+0

downvote? Pourquoi? + (15 caractères) – Behrooz

+1

Dunno, n'était pas moi. – wsanville

31

Pour autant que je sache, il n'y a pas de meilleure façon en termes de collaboration avec la bibliothèque de réflexion de façon plus intelligente. Cependant, vous pouvez utiliser LINQ pour rendre le code un peu plus agréable:

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' 

Je crois que cela vous aide à structurer le code de manière plus lisible.

12

Il y a toujours LINQ:

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

Si vous traitez régulièrement avec des attributs dans la réflexion, il est très, très pratique pour définir des méthodes d'extension. Vous verrez cela dans de nombreux projets. Celui-ci ici est celui que je souvent:

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

que vous pouvez utiliser comme typeof(Foo).HasAttribute<BarAttribute>();

D'autres projets (par exemple StructureMap) ont des classes de ReflectionHelper à part entière qui utilisent des arbres d'expression pour avoir une syntaxe bien à l'identité par exemple PropertyInfos. Utilisation ressemble alors que:

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

La solution que je finis par utiliser la plupart est basé sur de la réponse de Tomas Petricek. . Je veux habituellement faire quelque chose avec les deux l'attribut et la propriété.

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 - «Je veux généralement faire quelque chose avec l'attribut et la propriété» est ce que je cherchais - merci beaucoup de poster votre réponse! –

0

En plus de pré Vives réponses: il est préférable d'utiliser la méthode Any() au lieu de vérifier la longueur de la collection:

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