获取DisplayName属性的值


Answers:


85

尝试以下这些实用程序方法:

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

您能帮我找出遍历所有属性DisplayName的正确方法吗?stackoverflow.com/questions/12868901/…–
DmitryBoyko,2012年

1
@ rich-tebb当您具有[Display(Name =“ SomeProperty”,ResourceType = typeof(SomeResource))]时,这似乎不起作用,它不返回本地化名称。会尝试对其进行修改。
Matija Grcic 2013年

添加了一些代码片段,如何从DisplayAttribute中读取本地化的值。
Matija Grcic 2013年

1
公共静态T GetAttribute <T>(不能在非通用,非嵌套静态类中声明此扩展方法
MIKE 2016年

公共静态ThankYou
Ashraf Abusada

34

首先,您需要获取一个MemberInfo代表该属性的对象。您将需要进行某种形式的反思:

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

(我使用的是“旧式”反射,但是如果可以在编译时访问类型,则也可以使用表达式树)

然后,您可以获取属性并获取属性的值DisplayName

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

()括号是必需的拼写错误


4
如果displayNameAttribute为null,这将失败。而不是返回单个尝试返回FirstOrDefault(),而是检查此值是否为null。
rkmorgan

32

您需要获取PropertyInfo与该属性的关联(例如通过typeof(Class1).GetProperty("Name")),然后调用GetCustomAttributes

由于返回多个值,因此有点混乱-如果您需要从几个地方开始,则可能需要编写一个辅助方法来执行此操作。(该框架中某处可能已经有一个辅助方法,但是如果存在,我将不知道。)

编辑:由于leppie指出的那样,这样的方法:Attribute.GetCustomAttribute(MemberInfo, Type)


18
我们得到了Attribute.GetCustomAttribute(MemberInfo, Type) :) msdn.microsoft.com/en-us/library/ms130863
leppie 2011年

1
@leppie:哦,很好。不知道为什么我从没发现过。
乔恩·斯基特

2
@cesAR:您已经发布了指向问题的链接。但是请不要一般地这样做-在一个答案上链接到另一个问题的评论几乎是不合适的。
乔恩·斯基特

12

在具有Class1作为强类型视图模型的视图中:

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

我认为这应该是公认的答案。我认为它足够聪明,可以在内部使用缓存的元数据对象。任一种方式,简洁,简洁并使用.net自己的方法
胡须的骆驼

仅可通过System.Web.Mvc使用-并不是每个人都可以使用Web应用程序,即使在2020
。– Yoda

12

如果有人对使用DisplayAttributeResourceType从属性中获取本地化的字符串感兴趣,如下所示:

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

6
DisplayAttributeGetName方法。.NET 4+中不需要您的代码:msdn.microsoft.com/en-us/library/…–
Salar

1
@Salar没错,但是您会被误导-当指定ResourceType时,该GetName()方法仅返回Key,而不返回在资源文件中指定的Value。
马特·格里菲思

@MattGriffiths这个变量' displayAttribute '是什么?
Dark_Knight

@Dark_Knight可能是保存该显示属性查询结果的变量,有关如何执行此操作的示例,请参见stackoverflow.com/a/10048758/3941350
尤达(Yoda)

由撒拉族指出,这是更好地使用.GetName(),而不是上面的代码中,看到了问题,我与上面的代码在这里:stackoverflow.com/questions/43827360/...
JPTétreault

9

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

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

displayName 变量现在保存属性的值。


1
看起来很hacky
Kolob Canyon

4

我有这种通用的实用程序方法。我传入一个给定类型的列表(假设您有一个支持类),它会生成一个数据表,其属性为列标题,列表项为数据。

就像在标准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将“ Navigation”属性以虚拟形式放置。但是,如果您选择扩展此类,它也会过滤掉您自己的任何虚拟属性。因此,我更喜欢制作一个ViewModel并仅用所需的属性来装饰它,并根据需要显示名称属性,然后列出它们。

希望这可以帮助。


3
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(foo);

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

foo的实例在哪里Class1


2

我知道聚会晚了。

我用这个:

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

希望这可以帮助。


1

假设propertyPropertyInfo类型,您可以在一行中完成此操作:

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

1

试试这个代码:

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

它将为您提供data属性的值Name


0

请尝试以下代码,我认为这可以解决您的问题。

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

请添加一些说明/内联代码注释,以说明您的代码如何工作以及如何解决OP的查询。
Madhur Bhaiya,

0

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

测试方法输出:

测试方法输出

具有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;

}


GetPropertyInformation()在这种情况下不存在。我刚刚意识到,下面的答案中存在此代码
Klicker

0

如果相反

[DisplayName(“要命名的东西”)]

你用

[显示(名称=“名称的东西”)]

只是这样做:

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;
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.