Получить значение атрибута DisplayName

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

Как получить значение атрибута DisplayName в С#?

Ответ 1

Попробуйте использовать мои служебные методы:

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;
}

Использование:

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

Ответ 2

Вам нужно получить PropertyInfo, связанный с этим свойством (например, через typeof(Class1).GetProperty("Name")), а затем вызвать GetCustomAttributes.

Это немного беспорядочно из-за возврата нескольких значений. Возможно, вам захочется написать вспомогательный метод, чтобы сделать это, если вам нужно это из нескольких мест. (Возможно, в каком-то контексте может быть вспомогательный метод, но если есть, то я не знаю об этом.)

EDIT: Как отметил leppie, существует такой метод: Attribute.GetCustomAttribute(MemberInfo, Type)

Ответ 3

Во-первых, вам нужно получить объект MemberInfo, который представляет это свойство. Вам нужно будет сделать какую-то форму:

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

(Я использую отражение "старого стиля", но вы также можете использовать дерево выражений, если у вас есть доступ к типу во время компиляции)

Затем вы можете получить атрибут и получить значение свойства DisplayName:

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

() требуются скобки

Ответ 4

Если кто-то заинтересован в получении локализованной строки из свойства с помощью DisplayAttribute и ResourceType следующим образом:

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

Используйте следующее после displayAttribute != null (как показано выше @alex 'answer):

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();

Ответ 5

Внутри представления, которое имеет Class1, поскольку он строго типизировал модель представления:

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

Ответ 6

Хорошие классы от Rich Tebb! Я использовал DisplayAttribute, и код не работал у меня. Единственное, что я добавил, это обработка DisplayAttribute. Краткий поиск дал, что этот атрибут является новым для MVC3 и .Net 4 и делает почти то же самое и больше. Здесь приведена модифицированная версия метода:

 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;
            }
        }
    }

Ответ 7

У меня есть этот общий метод утилиты. Я перехожу в список определенного типа (предположим, что у вас есть поддерживающий класс), и он генерирует данные со свойствами, такими как заголовки столбцов и элементы списка как данные.

Как и в стандартном MVC, если у вас нет атрибута DisplayName, он будет возвращаться к имени свойства, поэтому вам нужно включить DisplayName, где оно отличается от имени свойства.

    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;
    }

Если есть более эффективный/безопасный способ сделать это, я бы добавил любую обратную связь. Прокомментированное предложение //Where отфильтровывает виртуальные свойства. Полезно, если вы используете классы моделей напрямую, поскольку EF добавляет свойства "Навигация" как виртуальные. Однако он также отфильтровывает любые ваши собственные виртуальные свойства, если вы решите расширить такие классы. По этой причине я предпочитаю создавать ViewModel и украшать его только необходимыми свойствами и отображать атрибуты имени по мере необходимости, а затем составлять их список.

Надеюсь, что это поможет.

Ответ 8

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

Переменная displayName теперь содержит значение свойства.

Ответ 9

PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(foo);

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

где foo является экземпляром Class1

Ответ 10

Предполагая property как PropertyInfo, вы можете сделать это в одной строке:

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

Ответ 11

Попробуйте этот код:

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

Он даст вам значение атрибута data Name.

Ответ 12

После ответа Rich Tebb и Matt Baker я хотел использовать методы ReflectionExtensions в запросе LINQ, но он не работал, поэтому я создал этот метод, чтобы он работал.

Если DisplayNameAttribute установлен, метод вернет его, в противном случае он вернет имя MemberInfo.

Метод испытания:

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)));
}

Тест метод вывода:

Test method output

Класс с атрибутом DisplayName1:

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; }
}

И метод расширения:

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;

}

Ответ 13

Пожалуйста, попробуйте ниже код, я думаю, что это решит вашу проблему.

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);
}