336 votes

Reflection - obtenir le nom et la valeur d'un attribut sur une propriété

J'ai une classe, appelons-la Livre, avec une propriété appelée Nom. Avec cette propriété, j'ai un attribut qui lui est associé.

public class Book
{
    [Author("AuthorName")]
    public string Name
    {
        get; private set; 
    }
}

Dans ma méthode principale, j'utilise la réflexion et je souhaite obtenir la paire clé-valeur de chaque attribut pour chaque propriété. Ainsi, dans cet exemple, je m'attends à voir "Author" pour le nom de l'attribut et "AuthorName" pour la valeur de l'attribut.

Question : Comment obtenir le nom et la valeur de l'attribut de mes propriétés à l'aide de Reflection ?

0 votes

Qu'est-ce qui se passe quand vous essayez d'accéder aux propriétés de cet objet par réflexion, êtes-vous bloqué quelque part ou voulez-vous du code pour la réflexion ?

394voto

Adam Markowitz Points 4358

Utilisez typeof(Book).GetProperties() pour obtenir un tableau de PropertyInfo instances. Utilisez ensuite GetCustomAttributes() sur chaque PropertyInfo pour voir si l'un d'entre eux a le Author Type d'attribut. Si c'est le cas, vous pouvez obtenir le nom de la propriété à partir de l'information sur la propriété et les valeurs de l'attribut à partir de l'attribut.

Quelque chose de ce genre pour rechercher dans un type les propriétés qui ont un type d'attribut spécifique et pour retourner les données dans un dictionnaire (notez que cela peut être rendu plus dynamique en passant les types dans la routine) :

public static Dictionary<string, string> GetAuthors()
{
    Dictionary<string, string> _dict = new Dictionary<string, string>();

    PropertyInfo[] props = typeof(Book).GetProperties();
    foreach (PropertyInfo prop in props)
    {
        object[] attrs = prop.GetCustomAttributes(true);
        foreach (object attr in attrs)
        {
            AuthorAttribute authAttr = attr as AuthorAttribute;
            if (authAttr != null)
            {
                string propName = prop.Name;
                string auth = authAttr.Name;

                _dict.Add(propName, auth);
            }
        }
    }

    return _dict;
}

20 votes

J'espérais que je n'aurais pas à lancer l'attribut.

0 votes

Prop.GetCustomAttributes(true) ne renvoie qu'un objet[]. Si vous ne voulez pas faire de cast, vous pouvez utiliser la réflexion sur les instances d'attributs elles-mêmes.

0 votes

Qu'est-ce que l'AttributAuteur ici ? S'agit-il d'une classe dérivée d'Attribute ? @Adam Markowitz

144voto

Valipour Points 7333

Pour obtenir tous les attributs d'une propriété dans un dictionnaire, utilisez ceci :

typeof(Book)
  .GetProperty("Name")
  .GetCustomAttributes(false) 
  .ToDictionary(a => a.GetType().Name, a => a);

n'oubliez pas de passer de false a true si vous souhaitez également inclure les attributs hérités.

4 votes

Cette solution fait effectivement la même chose que celle d'Adam, mais elle est beaucoup plus concise.

38 votes

Ajoutez .OfType<AuthorAttribue>() à l'expression au lieu de ToDictionary si vous n'avez besoin que d'attributs d'auteur et que vous voulez éviter un futur cast.

3 votes

Cela ne va-t-il pas lever une exception lorsqu'il y a deux attributs du même type sur la même propriété ?

92voto

maxspan Points 310

Si vous ne voulez qu'une valeur d'attribut spécifique, par exemple l'attribut Display, vous pouvez utiliser le code suivant :

var pInfo = typeof(Book).GetProperty("Name")
                             .GetCustomAttribute<DisplayAttribute>();
var name = pInfo.Name;

22voto

BrokenGlass Points 91618

Vous pouvez utiliser GetCustomAttributesData() y GetCustomAttributes() :

var attributeData = typeof(Book).GetProperty("Name").GetCustomAttributesData();
var attributes = typeof(Book).GetProperty("Name").GetCustomAttributes(false);

5 votes

Quelle est la différence ?

2 votes

@PrimeByDesign Le premier découvre comment pour instancier les attributs appliqués. Ce dernier instancie réellement ces attributs.

13voto

Marc Gravell Points 482669

Si vous voulez dire "pour les attributs qui prennent un paramètre, lister les noms des attributs et la valeur du paramètre", c'est plus facile dans .NET 4.5 grâce à la fonction CustomAttributeData API :

using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;

public static class Program
{
    static void Main()
    {
        PropertyInfo prop = typeof(Foo).GetProperty("Bar");
        var vals = GetPropertyAttributes(prop);
        // has: DisplayName = "abc", Browsable = false
    }
    public static Dictionary<string, object> GetPropertyAttributes(PropertyInfo property)
    {
        Dictionary<string, object> attribs = new Dictionary<string, object>();
        // look for attributes that takes one constructor argument
        foreach (CustomAttributeData attribData in property.GetCustomAttributesData()) 
        {

            if(attribData.ConstructorArguments.Count == 1)
            {
                string typeName = attribData.Constructor.DeclaringType.Name;
                if (typeName.EndsWith("Attribute")) typeName = typeName.Substring(0, typeName.Length - 9);
                attribs[typeName] = attribData.ConstructorArguments[0].Value;
            }

        }
        return attribs;
    }
}

class Foo
{
    [DisplayName("abc")]
    [Browsable(false)]
    public string Bar { get; set; }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X