web-dev-qa-db-fra.com

obtenir la valeur de l'attribut DisplayName

public class Class1
{
    [DisplayName("Something To Name")]
    public virtual string Name { get; set; }
}

Comment obtenir la valeur de l'attribut DisplayName en C #?

57
user550937

Essayez ces méthodes utilitaires à moi:

using System.ComponentModel;
using System.Globalization;
using System.Linq;


public static T GetAttribute<T>(this MemberInfo member, bool isRequired)
    where T : Attribute
{
    var attribute = member.GetCustomAttributes(typeof(T), false).SingleOrDefault();

    if (attribute == null && isRequired)
    {
        throw new ArgumentException(
            string.Format(
                CultureInfo.InvariantCulture, 
                "The {0} attribute must be defined on member {1}", 
                typeof(T).Name, 
                member.Name));
    }

    return (T)attribute;
}

public static string GetPropertyDisplayName<T>(Expression<Func<T, object>> propertyExpression)
{
    var memberInfo = GetPropertyInformation(propertyExpression.Body);
    if (memberInfo == null)
    {
        throw new ArgumentException(
            "No property reference expression was found.",
            "propertyExpression");
    }

    var attr = memberInfo.GetAttribute<DisplayNameAttribute>(false);
    if (attr == null)
    {
        return memberInfo.Name;
    }

    return attr.DisplayName;
}

public static MemberInfo GetPropertyInformation(Expression propertyExpression)
{
    Debug.Assert(propertyExpression != null, "propertyExpression != null");
    MemberExpression memberExpr = propertyExpression as MemberExpression;
    if (memberExpr == null)
    {
        UnaryExpression unaryExpr = propertyExpression as UnaryExpression;
        if (unaryExpr != null && unaryExpr.NodeType == ExpressionType.Convert)
        {
            memberExpr = unaryExpr.Operand as MemberExpression;
        }
    }

    if (memberExpr != null && memberExpr.Member.MemberType == MemberTypes.Property)
    {
        return memberExpr.Member;
    }

    return null;
}

L'utilisation serait:

string displayName = ReflectionExtensions.GetPropertyDisplayName<SomeClass>(i => i.SomeProperty);
68
Rich Tebb

Vous devez obtenir le PropertyInfo associé à la propriété (par exemple via typeof(Class1).GetProperty("Name")), puis appeler GetCustomAttributes .

C'est un peu compliqué à cause du retour de plusieurs valeurs - vous pouvez écrire une méthode d'assistance pour le faire si vous en avez besoin à plusieurs endroits. (Il se peut qu'il y ait déjà une méthode d'assistance dans le cadre quelque part, mais s'il n'y en a pas, je l'ignore.)

EDIT: Comme Leppie l’a fait remarquer, il existe une telle méthode : Attribute.GetCustomAttribute(MemberInfo, Type)

29
Jon Skeet

Tout d'abord, vous devez obtenir un objet MemberInfo qui représente cette propriété. Vous devrez faire une forme de réflexion:

MemberInfo property = typeof(Class1).GetProperty("Name");

(J'utilise une réflexion "à l'ancienne", mais vous pouvez également utiliser un arbre d'expression si vous avez accès au type au moment de la compilation)

Ensuite, vous pouvez récupérer l'attribut et obtenir la valeur de la propriété DisplayName:

var attribute = property.GetCustomAttributes(typeof(DisplayNameAttribute), true)
      .Cast<DisplayNameAttribute>().Single();
string displayName = attribute.DisplayName;

() les parenthèses sont obligatoires faute de frappe

25
R. Martinho Fernandes

Si quelqu'un souhaite obtenir la chaîne localisée à partir de la propriété avec DisplayAttribute et ResourceType, comme ceci:

[Display(Name = "Year", ResourceType = typeof(ArrivalsResource))]
public int Year { get; set; }

Utilisez ce qui suit après displayAttribute != null (comme indiqué ci-dessus par la réponse de @alex ):

ResourceManager resourceManager = new ResourceManager(displayAttribute.ResourceType);
var entry = resourceManager.GetResourceSet(Thread.CurrentThread.CurrentUICulture, true, true)
                           .OfType<DictionaryEntry>()
                           .FirstOrDefault(p => p.Key.ToString() == displayAttribute.Name);

return entry.Value.ToString();
11
Matija Grcic

Dans une vue ayant Class1 comme modèle de vue fortement typé:

ModelMetadata.FromLambdaExpression<Class1, string>(x => x.Name, ViewData).DisplayName;
10
Luke Bennett

De belles classes de Rich Tebb! J'utilise DisplayAttribute et le code ne fonctionne pas pour moi. La seule chose que j'ai ajoutée est la gestion de DisplayAttribute. Une brève recherche a révélé que cet attribut était nouveau dans MVC3 et .Net 4 et faisait presque la même chose et plus encore. Voici une version modifiée de la méthode:

 public static string GetPropertyDisplayString<T>(Expression<Func<T, object>> propertyExpression)
    {
        var memberInfo = GetPropertyInformation(propertyExpression.Body);
        if (memberInfo == null)
        {
            throw new ArgumentException(
                "No property reference expression was found.",
                "propertyExpression");
        }

        var displayAttribute = memberInfo.GetAttribute<DisplayAttribute>(false);

        if (displayAttribute != null)
        {
            return displayAttribute.Name;
        }
        else
        {
            var displayNameAttribute = memberInfo.GetAttribute<DisplayNameAttribute>(false);
            if (displayNameAttribute != null)
            {
                return displayNameAttribute.DisplayName;
            }
            else
            {
                return memberInfo.Name;
            }
        }
    }
6
alex

J'ai cette méthode d'utilité générique. Je passe dans une liste d'un type donné (en supposant que vous ayez une classe de support) et cela génère un datatable avec les propriétés comme en-tête de colonne et les éléments de liste comme données.

Tout comme dans MVC standard, si l'attribut DisplayName n'est pas défini, le nom de la propriété sera remplacé. Vous ne devez donc inclure que DisplayName s'il est différent du nom de la propriété.

    public DataTable BuildDataTable<T>(IList<T> data)
    {
        //Get properties
        PropertyInfo[] Props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
        //.Where(p => !p.GetGetMethod().IsVirtual && !p.GetGetMethod().IsFinal).ToArray(); //Hides virtual properties

        //Get column headers
        bool isDisplayNameAttributeDefined = false;
        string[] headers = new string[Props.Length];
        int colCount = 0;
        foreach (PropertyInfo prop in Props)
        {
            isDisplayNameAttributeDefined = Attribute.IsDefined(prop, typeof(DisplayNameAttribute));

            if (isDisplayNameAttributeDefined)
            {
                DisplayNameAttribute dna = (DisplayNameAttribute)Attribute.GetCustomAttribute(prop, typeof(DisplayNameAttribute));
                if (dna != null)
                    headers[colCount] = dna.DisplayName;
            }
            else
                headers[colCount] = prop.Name;

            colCount++;
            isDisplayNameAttributeDefined = false;
        }

        DataTable dataTable = new DataTable(typeof(T).Name);

        //Add column headers to datatable
        foreach (var header in headers)
            dataTable.Columns.Add(header);

        dataTable.Rows.Add(headers);

        //Add datalist to datatable
        foreach (T item in data)
        {
            object[] values = new object[Props.Length];
            for (int col = 0; col < Props.Length; col++)
                values[col] = Props[col].GetValue(item, null);

            dataTable.Rows.Add(values);
        }

        return dataTable;
    }

S'il existe un moyen plus efficace et plus sûr de le faire, j'apprécierais tout commentaire. La clause // Where commentée filtrera les propriétés virtuelles. Utile si vous utilisez directement des classes de modèle lorsque EF met dans les propriétés "Navigation" des propriétés virtuelles. Cependant, si vous choisissez d'étendre de telles classes, il filtrera également vos propres propriétés virtuelles. Pour cette raison, je préfère créer un ViewModel et le décorer avec uniquement les propriétés et les attributs de nom nécessaires, puis en dresser une liste.

J'espère que cela t'aides.

4
Francis Rodgers
 PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(foo);

            foreach (PropertyDescriptor property in properties)
            {
                if (property.Name == "Name")
                {
                    Console.WriteLine(property.DisplayName); //Something To Name
                }
            }

où foo est une instance de Class1

3
Foo
var propInfo = new Class1().GetType().GetProperty("Name");
var displayNameAttribute = propInfo.GetCustomAttributes(typeof(DisplayNameAttribute), false);
var displayName = displayNameAttribute[0] as DisplayNameAttribute).DisplayName;

La variable displayName contient maintenant la valeur de la propriété.

2

En supposant que property soit de type PropertyInfo, vous pouvez le faire en une seule ligne:

property.GetCustomAttributes(typeof(DisplayNameAttribute), true).Cast<DisplayNameAttribute>().Single().DisplayName
1

Essayez ce code:

EnumEntity.item.GetType().GetFields()[(int)EnumEntity.item].CustomAttributes.ToArray()[0].NamedArguments[0].TypedValue.ToString()

Cela vous donnera la valeur de l'attribut de données Name.

1
Rafael

suite à la réponse de Rich Tebb et Matt Baker, je voulais utiliser les méthodes ReflectionExtensions dans une requête linq mais cela n’a pas fonctionné, j’ai donc fait en sorte que cette méthode fonctionne: si DisplayNameAttribute est défini, elle le retournera sinon renvoyer le nom de membreinfo:

méthode d'essai:

static void Main(string[] args)
    {
        var lst = new List<Test>();
        lst.Add(new Test("coucou1", "kiki1"));
        lst.Add(new Test("coucou2", "kiki2"));
        lst.Add(new Test("coucou3", "kiki3"));
        lst.Add(new Test("coucou4", "kiki4"));
        lst.ForEach(i => Console.WriteLine(i.GetAttributeName<Test>(t => t.Name)+";"+i.GetAttributeName<Test>(t=>t.t2)));

    }

// résultat de la méthode de test:

 Test method output

// ci-dessous: la classe avec l'attribut DisplayName

public class Test
{
    public Test() { }
    public Test(string name, string T2)
    {
        Name = name;
        t2 = T2;
    }
    [DisplayName("toto")]
    public string Name { get; set; }
    public string t2 { get; set; }
}

// et la méthode d'extension:

public static string GetAttributeName<T>(this T itm, Expression<Func<T, object>> propertyExpression)

    {
        var memberInfo = GetPropertyInformation(propertyExpression.Body);
        if (memberInfo == null)
        {
            throw new ArgumentException(
                "No property reference expression was found.",
                "propertyExpression");
        }

        var pi = typeof(T).GetProperty(memberInfo.Name);
        var ret = pi.GetCustomAttributes(typeof(DisplayNameAttribute), true).Cast<DisplayNameAttribute>().SingleOrDefault();
        return ret != null ? ret.DisplayName : pi.Name;

    }
0
Xavave

S'il vous plaît essayer ci-dessous le code, je pense que cela résoudra votre problème.

var classObj = new Class1();
classObj.Name=>"StackOverflow";
var property= new Class1().GetType().GetProperty(nameof(classObj.Name));
var displayNameAttributeValue = (property ?? throw new 
InvalidOperationException()).GetCustomAttributes(typeof(DisplayNameAttribute)) as 
DisplayNameAttribute;   
if(displayNameAttributeValue != null)Console.WriteLine("{0} = 
{1} ",displayNameAttributeValue,classObj.Name);
0
Sid