关于c#:如何通过MVC razor代码获取Enum成员的显示名称属性?

How to get the Display Name Attribute of an Enum member via MVC razor code?

我的模型中有一个名为"promotion"的属性,它的类型是一个名为"userpromotion"的标志枚举。我的枚举成员的显示属性设置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[Flags]
public enum UserPromotion
{
    None = 0x0,

    [Display(Name ="Send Job Offers By Mail")]
    SendJobOffersByMail = 0x1,

    [Display(Name ="Send Job Offers By Sms")]
    SendJobOffersBySms = 0x2,

    [Display(Name ="Send Other Stuff By Sms")]
    SendPromotionalBySms = 0x4,

    [Display(Name ="Send Other Stuff By Mail")]
    SendPromotionalByMail = 0x8
}

现在,我希望能够在我的视图中创建say-ul,以显示我的"提升"属性的选定值。这是我迄今为止所做的,但问题是如何在这里获取显示名称?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<ul>

    @foreach (int aPromotion in @Enum.GetValues(typeof(UserPromotion)))
    {
        var currentPromotion = (int)Model.JobSeeker.Promotion;
        if ((currentPromotion & aPromotion) == aPromotion)
        {
       
<li>
Here I don't know how to get the display attribute of"currentPromotion".
</li>

        }
    }

</ul>


更新

第一个解决方案的重点是从枚举中获取显示名称。下面的代码应该是您的问题的确切解决方案。

可以将此帮助器类用于枚举:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;

public static class EnumHelper<T>
{
    public static IList<T> GetValues(Enum value)
    {
        var enumValues = new List<T>();

        foreach (FieldInfo fi in value.GetType().GetFields(BindingFlags.Static | BindingFlags.Public))
        {
            enumValues.Add((T)Enum.Parse(value.GetType(), fi.Name, false));
        }
        return enumValues;
    }

    public static T Parse(string value)
    {
        return (T)Enum.Parse(typeof(T), value, true);
    }

    public static IList<string> GetNames(Enum value)
    {
        return value.GetType().GetFields(BindingFlags.Static | BindingFlags.Public).Select(fi => fi.Name).ToList();
    }

    public static IList<string> GetDisplayValues(Enum value)
    {
        return GetNames(value).Select(obj => GetDisplayValue(Parse(obj))).ToList();
    }

    private static string lookupResource(Type resourceManagerProvider, string resourceKey)
    {
        foreach (PropertyInfo staticProperty in resourceManagerProvider.GetProperties(BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public))
        {
            if (staticProperty.PropertyType == typeof(System.Resources.ResourceManager))
            {
                System.Resources.ResourceManager resourceManager = (System.Resources.ResourceManager)staticProperty.GetValue(null, null);
                return resourceManager.GetString(resourceKey);
            }
        }

        return resourceKey; // Fallback with the key name
    }

    public static string GetDisplayValue(T value)
    {
        var fieldInfo = value.GetType().GetField(value.ToString());

        var descriptionAttributes = fieldInfo.GetCustomAttributes(
            typeof(DisplayAttribute), false) as DisplayAttribute[];

        if (descriptionAttributes[0].ResourceType != null)
            return lookupResource(descriptionAttributes[0].ResourceType, descriptionAttributes[0].Name);

        if (descriptionAttributes == null) return string.Empty;
        return (descriptionAttributes.Length > 0) ? descriptionAttributes[0].Name : value.ToString();
    }
}

然后您可以在视图中使用它,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<ul>

    @foreach (var value in @EnumHelper<UserPromotion>.GetValues(UserPromotion.None))
    {
         if (value == Model.JobSeeker.Promotion)
        {
            var description = EnumHelper<UserPromotion>.GetDisplayValue(value);
           
<li>
@Html.DisplayFor(e => description )
</li>

        }
    }

</ul>

希望它有帮助!:)


一行程序-流利的语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static class Extensions
{
    /// <summary>
    ///     A generic extension method that aids in reflecting
    ///     and retrieving any attribute that is applied to an `Enum`.
    /// </summary>
    public static TAttribute GetAttribute<TAttribute>(this Enum enumValue)
            where TAttribute : Attribute
    {
        return enumValue.GetType()
                        .GetMember(enumValue.ToString())
                        .First()
                        .GetCustomAttribute<TAttribute>();
    }
}

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public enum Season
{
   [Display(Name ="It's autumn")]
   Autumn,

   [Display(Name ="It's winter")]
   Winter,

   [Display(Name ="It's spring")]
   Spring,

   [Display(Name ="It's summer")]
   Summer
}

public class Foo
{
    public Season Season = Season.Summer;

    public void DisplayName()
    {
        var seasonDisplayName = Season.GetAttribute<DisplayAttribute>();
        Console.WriteLine("Which season is it?");
        Console.WriteLine (seasonDisplayName.Name);
    }
}

产量

Which season is it?
It's summer


基于Aydin的伟大答案,这里有一个不需要任何类型参数的扩展方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
using System;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;

public static class EnumExtensions
{
    public static string GetDisplayName(this Enum enumValue)
    {
        return enumValue.GetType()
                        .GetMember(enumValue.ToString())
                        .First()
                        .GetCustomAttribute<DisplayAttribute>()
                        .GetName();
    }
}

注意:应使用getname()而不是name属性。这样可以确保在使用ResourceType属性属性时返回本地化字符串。

例子

要使用它,只需引用视图中的枚举值。

1
2
3
4
5
@{
    UserPromotion promo = UserPromotion.SendJobOffersByMail;
}

Promotion: @promo.GetDisplayName()

产量

晋升:通过邮件发送工作邀请


基于Aydin的回答,我建议使用一种"不那么重复"的实现(因为我们可以很容易地从Enum值本身获得Type,而不是将其作为参数提供??

1
2
3
4
5
6
7
public static string GetDisplayName(this Enum enumValue)
{
    return enumValue.GetType().GetMember(enumValue.ToString())
                   .First()
                   .GetCustomAttribute<DisplayAttribute>()
                   .Name;
}

编辑(基于@vahagn nahapetyan的评论)

1
2
3
4
5
6
7
8
public static string GetDisplayName(this Enum enumValue)
{
    return enumValue.GetType()?
                    .GetMember(enumValue.ToString())?
                    .First()?
                    .GetCustomAttribute<DisplayAttribute>()?
                    .Name;
}

现在我们可以非常干净地使用它:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public enum Season
{
    [Display(Name ="The Autumn")]
    Autumn,

    [Display(Name ="The Weather")]
    Winter,

    [Display(Name ="The Tease")]
    Spring,

    [Display(Name ="The Dream")]
    Summer
}

Season.Summer.GetDisplayName();

结果是

"The Dream"


如果您使用的是MVC 5.1或更高版本,那么有更简单、更清晰的方法:只需使用数据注释(来自System.ComponentModel.DataAnnotations名称空间),如下所示:

1
2
3
4
5
6
7
8
9
public enum Color
{
    [Display(Name ="Dark red")]
    DarkRed,
    [Display(Name ="Very dark red")]
    VeryDarkRed,
    [Display(Name ="Red or just black?")]
    ReallyDarkRed
}

在视图中,只需将其放入适当的HTML助手中:

1
@Html.EnumDropDownListFor(model => model.Color)


可以使用type.getmember方法,然后使用反射获取属性信息:

1
2
3
4
5
6
// display attribute of"currentPromotion"

var type = typeof(UserPromotion);
var memberInfo = type.GetMember(currentPromotion.ToString());
var attributes = memberInfo[0].GetCustomAttributes(typeof(DisplayAttribute), false);
var description = ((DisplayAttribute)attributes[0]).Name;

这里也有一些类似的帖子:

获取枚举值的属性

如何使MVC3显示为显示枚举的显示属性的值?


基于托德的伟大答案,这是建立在艾丁伟大答案的基础上的,这里有一个不需要任何类型参数的通用扩展方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/// <summary>
/// Gets human-readable version of enum.
/// </summary>
/// <returns>DisplayAttribute.Name property of given enum.</returns>
public static string GetDisplayName<T>(this T enumValue) where T : IComparable, IFormattable, IConvertible
{
    if (!typeof(T).IsEnum)
        throw new ArgumentException("Argument must be of type Enum");

    DisplayAttribute displayAttribute = enumValue.GetType()
                                                 .GetMember(enumValue.ToString())
                                                 .First()
                                                 .GetCustomAttribute<DisplayAttribute>();

    string displayName = displayAttribute?.GetName();

    return displayName ?? enumValue.ToString();
}

我在我的项目中需要这样做,因为类似下面的代码(不是枚举的每个成员都有一个DisplayAttribute)不适用于todd的解决方案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class MyClass
{
    public enum MyEnum
    {
        [Display(Name="ONE")]
        One,
        // No DisplayAttribute
        Two
    }
    public void UseMyEnum()
    {
        MyEnum foo = MyEnum.One;
        MyEnum bar = MyEnum.Two;
        Console.WriteLine(foo.GetDisplayName());
        Console.WriteLine(bar.GetDisplayName());
    }
}
// Output:
//
// ONE
// Two

如果这是一个简单问题的复杂解决方案,请告诉我,但这是我使用的修复方法。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<ul>

    @foreach (int aPromotion in @Enum.GetValues(typeof(UserPromotion)))
    {
        var currentPromotion = (int)Model.JobSeeker.Promotion;
        if ((currentPromotion & aPromotion) == aPromotion)
        {
       
<li>
@Html.DisplayFor(e => currentPromotion)
</li>

        }
    }

</ul>

要访问该属性,需要使用一些反射:

1
2
3
4
var type = typeof(UserPromotion);
var member = type.GetMember(Model.JobSeeker.Promotion.ToString());
var attributes = member[0].GetCustomAttributes(typeof(DisplayAttribute), false);
var name = ((DisplayAttribute)attributes[0]).Name;

我建议将此方法包装在扩展方法中,或者在视图模型中执行此操作。


我很抱歉这么做,但我不能像现在那样使用其他任何答案,也没有时间在评论中加以讨论。

使用C 6语法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
static class EnumExtensions
{
    /// returns the localized Name, if a [Display(Name="Localised Name")] attribute is applied to the enum member
    /// returns null if there isnt an attribute
    public static string DisplayNameOrEnumName(this Enum value)
    // => value.DisplayNameOrDefault() ?? value.ToString()
    {
        // More efficient form of ^ based on http://stackoverflow.com/a/17034624/11635
        var enumType = value.GetType();
        var enumMemberName = Enum.GetName(enumType, value);
        return enumType
            .GetEnumMemberAttribute<DisplayAttribute>(enumMemberName)
            ?.GetName() // Potentially localized
            ?? enumMemberName; // Or fall back to the enum name
    }

    /// returns the localized Name, if a [Display] attribute is applied to the enum member
    /// returns null if there is no attribute
    public static string DisplayNameOrDefault(this Enum value) =>
        value.GetEnumMemberAttribute<DisplayAttribute>()?.GetName();

    static TAttribute GetEnumMemberAttribute<TAttribute>(this Enum value) where TAttribute : Attribute =>
        value.GetType().GetEnumMemberAttribute<TAttribute>(value.ToString());

    static TAttribute GetEnumMemberAttribute<TAttribute>(this Type enumType, string enumMemberName) where TAttribute : Attribute =>
        enumType.GetMember(enumMemberName).Single().GetCustomAttribute<TAttribute>();
}

在Aydin和Todd答案的基础上,这里还有一个扩展方法,它还允许您从资源文件中获取名称。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
using AppResources;
using System;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;
using System.Resources;

public static class EnumExtensions
{
    public static string GetDisplayName(this Enum enumValue)
    {
        var enumMember= enumValue.GetType()
                        .GetMember(enumValue.ToString());

        DisplayAttribute displayAttrib = null;
        if (enumMember.Any()) {
            displayAttrib = enumMember
                        .First()
                        .GetCustomAttribute<DisplayAttribute>();
        }

        string name = null;
        Type resource = null;

        if (displayAttrib != null)
        {
            name = displayAttrib.Name;
            resource = displayAttrib.ResourceType;
        }

        return String.IsNullOrEmpty(name) ? enumValue.ToString()
            : resource == null ?  name
            : new ResourceManager(resource).GetString(name);
    }
}

并使用它

1
2
3
4
5
public enum Season
{
    [Display(ResourceType = typeof(Resource), Name = Season_Summer")]
    Summer
}


核心2.1,

1
2
3
4
5
6
7
public static string GetDisplayName(Enum enumValue)
{
  return enumValue.GetType()?
 .GetMember(enumValue.ToString())?[0]?
 .GetCustomAttribute<DisplayAttribute>()?
 .Name;
}

基于前面的答案,我创建了这个舒适的助手,以可读的方式支持所有DisplayAttribute属性:

16


使用MVC5,您可以使用:

25

然后,如果要创建下拉选择器,可以使用:

1
@Html.EnumDropdownListFor(expression: model => model.PromotionSelector, optionLabel:"Select")

我试着把它作为一个编辑来做,但被拒绝了,我不明白为什么。

如果您使用一个混合了自定义属性和普通项的枚举来调用它,那么上面将抛出一个异常,例如。

1
2
3
4
5
6
7
8
public enum CommentType
{
    All = 1,
    Rent = 2,
    Insurance = 3,
    [Display(Name="Service Charge")]
    ServiceCharge = 4
}

所以我稍微修改了代码,以便在尝试访问自定义属性之前检查它们,如果没有找到,则使用名称。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;

public static class EnumHelper<T>
{
    public static IList<T> GetValues(Enum value)
    {
        var enumValues = new List<T>();

        foreach (FieldInfo fi in value.GetType().GetFields(BindingFlags.Static | BindingFlags.Public))
        {
            enumValues.Add((T)Enum.Parse(value.GetType(), fi.Name, false));
        }
        return enumValues;
    }

    public static T Parse(string value)
    {
        return (T)Enum.Parse(typeof(T), value, true);
    }

    public static IList<string> GetNames(Enum value)
    {
        return value.GetType().GetFields(BindingFlags.Static | BindingFlags.Public).Select(fi => fi.Name).ToList();
    }

    public static IList<string> GetDisplayValues(Enum value)
    {
        return GetNames(value).Select(obj => GetDisplayValue(Parse(obj))).ToList();
    }

    private static string lookupResource(Type resourceManagerProvider, string resourceKey)
    {
        foreach (PropertyInfo staticProperty in resourceManagerProvider.GetProperties(BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public))
        {
            if (staticProperty.PropertyType == typeof(System.Resources.ResourceManager))
            {
                System.Resources.ResourceManager resourceManager = (System.Resources.ResourceManager)staticProperty.GetValue(null, null);
                return resourceManager.GetString(resourceKey);
            }
        }

        return resourceKey; // Fallback with the key name
    }

    public static string GetDisplayValue(T value)
    {
        var fieldInfo = value.GetType().GetField(value.ToString());

        var descriptionAttributes = fieldInfo.GetCustomAttributes(
            typeof(DisplayAttribute), false) as DisplayAttribute[];

        if (descriptionAttributes.Any() && descriptionAttributes[0].ResourceType != null)
            return lookupResource(descriptionAttributes[0].ResourceType, descriptionAttributes[0].Name);

        if (descriptionAttributes == null) return string.Empty;
        return (descriptionAttributes.Length > 0) ? descriptionAttributes[0].Name : value.ToString();
    }
}

我想为依赖于区域性的getDisplayName枚举扩展做出贡献。希望这对像我一样在谷歌上搜索这个答案的人有用:

正如Aydin Adn和Todd提到的"Standart"方式:

1
2
3
4
5
6
7
8
9
    public static string GetDisplayName(this Enum enumValue)
    {
        return enumValue
            .GetType()
            .GetMember(enumValue.ToString())
            .First()
            .GetCustomAttribute<DisplayAttribute>()
            .GetName();
    }

"文化依赖"方式:

1
2
3
4
5
6
7
8
9
10
11
12
    public static string GetDisplayName(this Enum enumValue, CultureInfo ci)
    {
        var displayAttr = enumValue
            .GetType()
            .GetMember(enumValue.ToString())
            .First()
            .GetCustomAttribute<DisplayAttribute>();

        var resMan = displayAttr.ResourceType?.GetProperty(@"ResourceManager", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).GetValue(null, null) as ResourceManager;

        return resMan?.GetString(displayAttr.Name, ci) ?? displayAttr.GetName();
    }