Vérifier si la propriété a un attribut


158

Étant donné une propriété dans une classe, avec des attributs - quel est le moyen le plus rapide de déterminer si elle contient un attribut donné? Par exemple:

    [IsNotNullable]
    [IsPK]
    [IsIdentity]
    [SequenceNameAttribute("Id")]
    public Int32 Id
    {
        get
        {
            return _Id;
        }
        set
        {
            _Id = value;
        }
    }

Quelle est la méthode la plus rapide pour déterminer qu'elle possède par exemple l'attribut "IsIdentity"?

Réponses:


280

Il n'y a pas de moyen rapide de récupérer les attributs. Mais le code devrait ressembler à ceci (crédit à Aaronaught ):

var t = typeof(YourClass);
var pi = t.GetProperty("Id");
var hasIsIdentity = Attribute.IsDefined(pi, typeof(IsIdentity));

Si vous avez besoin de récupérer les propriétés d'attribut,

var t = typeof(YourClass);
var pi = t.GetProperty("Id");
var attr = (IsIdentity[])pi.GetCustomAttributes(typeof(IsIdentity), false);
if (attr.Length > 0) {
    // Use attr[0], you'll need foreach on attr if MultiUse is true
}

63
Si vous avez seulement besoin de vérifier l'existence de l'attribut, et de ne récupérer aucune information à partir de celui-ci, l'utilisation Attribute.IsDefinedéliminera une ligne de code et les tableaux / transtypages laids.
Aaronaught le

4
Quelque chose que je viens de rencontrer avec ceci est que certains attributs ont un type différent de leur nom d'attribut. Par exemple "NotMapped" dans System.ComponentModel.DataAnnotations.Schema est utilisé comme [NotMapped]dans la classe mais pour le détecter, vous devez utiliserAttribute.IsDefined(pi, typeof(NotMappedAttribute))
Qjimbo

2
Peut-être plus facile d'utiliser la surcharge générique:IsIdentity[] attr = pi.GetCustomAttributes<IsIdentity>(false);
Mojtaba

@Qjimbo (ou probablement quelqu'un d'autre qui lit) Les attributs sont généralement utilisés sans la partie "Attribut" de leur nom, mais peuvent l'être. Une convention vous permet de l'exclure, donc généralement le type réel a un attribut à la fin de son nom, mais il n'est tout simplement pas utilisé.
Jim Wolff

44

Si vous utilisez .NET 3.5, vous pouvez essayer les arborescences d'expressions. C'est plus sûr que la réflexion:

class CustomAttribute : Attribute { }

class Program
{
    [Custom]
    public int Id { get; set; }

    static void Main()
    {
        Expression<Func<Program, int>> expression = p => p.Id;
        var memberExpression = (MemberExpression)expression.Body;
        bool hasCustomAttribute = memberExpression
            .Member
            .GetCustomAttributes(typeof(CustomAttribute), false).Length > 0;
    }
}

7
Pour info, une question a été posée sur votre réponse. stackoverflow.com/questions/4158996/…
Greg

12

Vous pouvez utiliser une méthode commune (générique) pour lire un attribut sur un MemberInfo donné

public static bool TryGetAttribute<T>(MemberInfo memberInfo, out T customAttribute) where T: Attribute {
                var attributes = memberInfo.GetCustomAttributes(typeof(T), false).FirstOrDefault();
                if (attributes == null) {
                    customAttribute = null;
                    return false;
                }
                customAttribute = (T)attributes;
                return true;
            }

7

Pour mettre à jour et / ou améliorer la réponse de @Hans Passant, je séparerais la récupération de la propriété en une méthode d'extension. Cela a l'avantage supplémentaire de supprimer la chaîne magique désagréable dans la méthode GetProperty ()

public static class PropertyHelper<T>
{
    public static PropertyInfo GetProperty<TValue>(
        Expression<Func<T, TValue>> selector)
    {
        Expression body = selector;
        if (body is LambdaExpression)
        {
            body = ((LambdaExpression)body).Body;
        }
        switch (body.NodeType)
        {
            case ExpressionType.MemberAccess:
                return (PropertyInfo)((MemberExpression)body).Member;
            default:
                throw new InvalidOperationException();
        }
    }
}

Votre test est alors réduit à deux lignes

var property = PropertyHelper<MyClass>.GetProperty(x => x.MyProperty);
Attribute.IsDefined(property, typeof(MyPropertyAttribute));

7

Si vous essayez de le faire dans une bibliothèque de classes portable PCL (comme moi), voici comment vous pouvez le faire :)

public class Foo
{
   public string A {get;set;}

   [Special]
   public string B {get;set;}   
}

var type = typeof(Foo);

var specialProperties = type.GetRuntimeProperties()
     .Where(pi => pi.PropertyType == typeof (string) 
      && pi.GetCustomAttributes<Special>(true).Any());

Vous pouvez ensuite vérifier le nombre de propriétés qui ont cette propriété spéciale si nécessaire.


7

Cela peut maintenant être fait sans arbres d'expression et méthodes d'extension de manière sûre avec la nouvelle fonctionnalité C # nameof()comme celle-ci:

Attribute.IsDefined(typeof(YourClass).GetProperty(nameof(YourClass.Id)), typeof(IsIdentity));

nameof () a été introduit en C # 6


6

Vous pouvez utiliser la méthode Attribute.IsDefined

https://msdn.microsoft.com/en-us/library/system.attribute.isdefined(v=vs.110).aspx

if(Attribute.IsDefined(YourProperty,typeof(YourAttribute)))
{
    //Conditional execution...
}

Vous pouvez fournir la propriété que vous recherchez spécifiquement ou vous pouvez les parcourir toutes en utilisant la réflexion, quelque chose comme:

PropertyInfo[] props = typeof(YourClass).GetProperties();

Cela ne compile pas. Vous ne pouvez pas utiliser [] autour de YourProperty ou YourAttribute
lance le

Chaque réponse précédente a utilisé des hypothèses sur les noms de classe, de propriété et d'attribut que j'ai suivies.
Francis Musignac le

Apparaît corrigé maintenant.
lance le

2

C'est une question assez ancienne mais j'ai utilisé

Ma méthode a ce paramètre mais il pourrait être construit:

Expression<Func<TModel, TValue>> expression

Puis dans la méthode ceci:

System.Linq.Expressions.MemberExpression memberExpression 
       = expression.Body as System.Linq.Expressions.MemberExpression;
Boolean hasIdentityAttr = System.Attribute
       .IsDefined(memberExpression.Member, typeof(IsIdentity));
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.