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

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

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

19 ответов

Попробуйте мои полезные методы:

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

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

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

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

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

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

() скобки обязательны для опечатки

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

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

РЕДАКТИРОВАТЬ: Как отметил Леппи, есть такой метод: Attribute.GetCustomAttribute(MemberInfo, Type)

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

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

Используйте следующее после displayAttribute != null (как показано выше ответом @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();
var propInfo = new Class1().GetType().GetProperty("Name");
var displayNameAttribute = propInfo.GetCustomAttributes(typeof(DisplayNameAttribute), false);
var displayName = displayNameAttribute[0] as DisplayNameAttribute).DisplayName;

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

Изнутри представления, имеющего Class1 в качестве строго типизированной модели представления:

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

Хорошие уроки от 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;
            }
        }
    }

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

Как и в стандартном 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 и украсить его только необходимыми свойствами и отображаемыми атрибутами по мере необходимости, а затем составить их список.

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

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

property.GetCustomAttributes(typeof(DisplayNameAttribute), true).Cast<DisplayNameAttribute>().Single().DisplayName
 PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(foo);

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

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

Я знаю, что поздно на вечеринку.

Я использую это:

public static string GetPropertyDisplayName(PropertyInfo pi)
{
  var dp = pi.GetCustomAttributes(typeof(DisplayNameAttribute), true).Cast<DisplayNameAttribute>().SingleOrDefault();
  return dp != null ? dp.DisplayName : pi.Name;
}

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

если вы здесь для [Display(Name="")] ниже код может помочь:

      var props = yourObject.GetType().GetProperties();
foreach (var item in props)
{
   string title = item.GetCustomAttributes(typeof(DisplayAttribute), true).Cast<DisplayAttribute>().SingleOrDefault()?.Name;
}

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

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

Это даст вам значение атрибута данных Name,

Это работает, спасибо кому-то выше:

      foreach (PropertyInfo pi in properties)
{
    var propName = pi.Name;
    var dp = pi.GetCustomAttributes(typeof(DisplayNameAttribute), true).Cast<DisplayNameAttribute>().SingleOrDefault();
    if (dp != null)
    {
        propName = dp.DisplayName; 
    }
}
      PropertyInfo[] properties = typeof(T).GetProperties();
String displayName = null;
foreach (PropertyInfo pi in properties){
     var displayAttribute = pi.GetCustomAttribute(typeof(DisplayAttribute));
    if (displayAttribute != null)
                {
                    displayName = (displayAttribute as DisplayAttribute).GetName();
                }
            }

После ответа Рича Тебба и Мэтта Бейкера я хотел использовать методы ReflectionExtensions в запросе linq, но он не работал, поэтому я создал этот метод для его работы: если задан DisplayNameAttribute, метод вернет его, иначе он будет вернуть имя участника:

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

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

    }

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

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

// ниже: класс с атрибутом 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; }
}

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

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;

    }

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

var classObj = new Class1();
classObj.Name=>"Stackru";
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);

Если вместо этого

[DisplayName("Что-то, что нужно назвать")]

ты используешь

[Display(Name = "Something To Name")]

Просто сделай это:

private string GetDisplayName(Class1 class1)
{
    string displayName = string.Empty;

    string propertyName = class1.Name.GetType().Name;

    CustomAttributeData displayAttribute = class1.GetType().GetProperty(propertyName).CustomAttributes.FirstOrDefault(x => x.AttributeType.Name == "DisplayAttribute");

    if (displayAttribute != null)
    {
        displayName = displayAttribute.NamedArguments.FirstOrDefault().TypedValue.Value;
    }

    return displayName;
}

Этот код сработал для меня...

Определение класса:

      using System.ComponentModel.DataAnnotations;

public class Class1{
     [Display(Name = "Something To Name")]
     public string PropertyOfMyClass1{ get; set; } 
 }

в вашем собственном методе:

      using System.Web.Mvc;

string displayName = ModelMetadata.FromLambdaExpression(x => x.PropertyOfMyClass1, new ViewDataDictionary<Class1>()).DisplayName;

Результат:

displayName --> «Что-то, что можно назвать»

в вашем изменении кодаPropertyOfMyClass1иClass1со своими ценностями.

Другие вопросы по тегам