Làm cách nào để có được Thuộc tính Tên hiển thị của thành viên Enum thông qua mã dao cạo MVC?


211

Tôi đã có một tài sản trong mô hình của mình được gọi là "Khuyến mãi" rằng loại của nó là một cờ enum gọi là "UserPromotion". Các thành viên của enum của tôi có các thuộc tính hiển thị được đặt như sau:

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

Bây giờ tôi muốn có thể tạo ra một ul trong quan điểm của mình để hiển thị các giá trị được chọn của thuộc tính "Khuyến mãi" của tôi. Đây là những gì tôi đã làm cho đến nay nhưng vấn đề là làm thế nào tôi có thể có được tên hiển thị ở đây?

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

12
MVC5 không hỗ trợ thuộc tính DisplayName trên enums.
Bart Calix đến

10
Để rõ ràng hơn: Chỉ System.ComponentModel.DataAnnotations.DisplayAttribute. Không phải System.ComponentModel.DisplayNameAttribute.
kamranicus

1
Điều này bao gồm việc sử dụng sự phản chiếu và do đó ảnh hưởng đến hiệu suất? 'vì điều này sẽ được gọi là RẤT NHIỀU thời gian.
Nico

Câu trả lời:


182

CẬP NHẬT

Giải pháp đầu tiên là tập trung vào việc lấy tên hiển thị từ enum. Mã dưới đây nên là giải pháp chính xác cho vấn đề của bạn.

Bạn có thể sử dụng lớp trợ giúp này cho enums:

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

Và sau đó bạn có thể sử dụng nó trong quan điểm của bạn như sau:

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

Hy vọng nó giúp! :)


8
Tất cả các câu trả lời đều sử dụng .ToString, nhưng từ stackoverflow.com/q/483794/179311 , nó nói sẽ sử dụng Enum.GetNamethay thế.
bradlis7

value.GetType (). GetField (value.ToString ()) chính xác là những gì tôi đang tìm kiếm!
cdie

Câu trả lời này là tốt với một số kiểm tra null được thêm vào, nhưng nếu bạn không sử dụng dotfuscation, câu trả lời tại stackoverflow.com/a/4412730/852806 có vẻ đơn giản hơn.
HockeyJ

5
Trước GetDisplayValuetiên bạn nên kiểm tra descriptionAttributes == nulltrước khi bạn cố gắng truy cập vào mảng : descriptionAttributes[0]. Nếu không, bạn có thể đưa ra một ngoại lệ và dòng bên dưới nơi bạn kiểm tra null sẽ không bao giờ đúng.
Robert S.

Tôi muốn đề xuất thay đổi vị thành niên: IList tĩnh công khai <T> GetValues ​​(giá trị Enum) có thể là IList tĩnh công khai <T> GetValues ​​(giá trị T). EnumHelper <T> to => lớp tĩnh công khai EnumHelper <T> trong đó T: struct, IConvertible. Có lẽ tĩnh điện? static EnumHelper () {if (! typeof (T) .IsEnum) {throw new ArgumentException ("T phải là một kiểu liệt kê"); }}
Tom

172

Một lớp lót - Cú pháp trôi chảy

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

Thí dụ

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

Đầu ra

Mùa nào vậy
Mùa hè đến rồi


2
Không tồn tại định nghĩa về GetCustomAttribution
Tito

3
@Tito đảm bảo rằng dự án của bạn đang nhắm mục tiêu .NET Framework 4.5và bạn bao gồm các không gian tên sauSystem.Net System.ComponentModel.DataAnnotations
Aydin

8
sử dụng System.Reflection; sử dụng System.ComponentModel.DataAnnotations; Đã cần cho tôi.
tội Lolwut

1
Thật là một quy ước đặt tên khủng khiếp!
tò mòBoy

@cantlyBoy Làm thế nào là GetAttribute<TAttribute>một quy ước đặt tên khủng khiếp? Nó lấy thuộc tính bạn chỉ định và sử dụng vỏ pascal như tất cả các phương thức công khai nên.
Aydin

137

Dựa trên câu trả lời tuyệt vời của Aydin , đây là một phương pháp mở rộng không yêu cầu bất kỳ tham số loại nào.

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

LƯU Ý: Nên sử dụng GetName () thay cho thuộc tính Tên. Điều này đảm bảo rằng chuỗi được bản địa hóa sẽ được trả về nếu sử dụng thuộc tính ResourceType.

Thí dụ

Để sử dụng nó, chỉ cần tham khảo giá trị enum trong chế độ xem của bạn.

@{
    UserPromotion promo = UserPromotion.SendJobOffersByMail;
}

Promotion: @promo.GetDisplayName()

Đầu ra

Khuyến mãi: Gửi lời mời làm việc qua thư


4
Ngoài ra để thêm các không gian tên sau: bằng cách sử dụng Hệ thống; sử dụng System.ComponentModel.DataAnnotations; sử dụng System.Linq; sử dụng System.Reflection;
Peter Kerr

Giải pháp khéo léo, nhưng tôi nhận được {"Mẫu chỉ có thể được sử dụng với quyền truy cập trường, quyền truy cập thuộc tính, chỉ mục mảng một chiều hoặc biểu thức chỉ mục tùy chỉnh tham số đơn."}
Casey Crookston

Nhìn vào các câu trả lời SO khác cho thông báo lỗi này (tôi không quen với nó), có vẻ như bạn có thể đang sử dụng từ trong phương thức trình trợ giúp Html (như @Html.DisplayFor(m => m.myEnum.GetDisplayName()), nó sẽ không hoạt động, vì họ hy vọng biểu thức được đánh giá sẽ mang lại một thuộc tính hoặc một cái gì đó tương tự. Bạn nên sử dụng giá trị enum trần như trong ví dụ trên.
Todd

7
Tôi đã thêm một kiểm tra tham chiếu null vào kết quả GetCustomAttribute<DisplayAttribute>()vì đối với một số Enums có thể điều này không có mặt. Nó rơi trở lại enumValue.ToString()nếu DisplayAttribution không có mặt.
H Dog

1
Tôi đã sử dụng điều này để tạo ra một List<SelectListItem>Enum với tất cả các DisplayAttribute.Namechú thích riêng lẻ - điều này hoạt động hoàn hảo, cảm ơn bạn !! public List<SelectListItem> MySelectListItem = new List<SelectListItem>(); foreach (MyEnum MyEnum in Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>().Where(x => x != MyEnum.Default)) { MySelectListItem.Add(new SelectListItem() { Text = MyEnum.GetDisplayName(), Value = ((int)MyEnum).ToString() }); }
Phễu

61

Dựa trên câu trả lời của Aydin tôi sẽ đề nghị một ít "duplicatious" thực hiện (vì chúng ta có thể dễ dàng có được Typetừ Enumgiá trị bản thân, thay vì cung cấp nó như là một tham số 😉:

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

EDIT (dựa trên nhận xét của @Vahagn Nahapetyan)

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

Bây giờ chúng ta có thể sử dụng nó rất sạch theo cách này:

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

Kết quả nào

"Giấc mơ"


1
Cho đến nay, đơn giản nhất và dễ nhất trong tất cả các câu trả lời. Cảm ơn!
Casey Crookston

Bạn nên cẩn thận với .irst (). Điều này sẽ đưa ra một ngoại lệ, ví dụ nếu tên enum của bạn là "Bằng"
Vahagn Nahapetyan

Tôi hiểu "nguy hiểm" với First (). Trong trường hợp cụ thể này, nó dường như không phải là một vấn đề. Bởi vì nó là một phương thức mở rộng trong đó thisphải là giá trị Enum hợp lệ (không phải null). Nếu không, gọi phương thức sẽ ném (đó là trách nhiệm của mã gọi). Điều này làm cho điều đó GetType()chắc chắn sẽ cung cấp Loại Enum chính xác, trong đó enumvaluechắc chắn sẽ là thành viên. Nhưng GetCustomAttribution có thể trả về giá trị null nên tôi đã cung cấp một phiên bản phương thức không đặc biệt để trả về null khi chuỗi lệnh gọi phương thức có giá trị trả về null ở đâu đó. Cảm ơn!
Bernoulli IT

1
Đối với biến thể thứ hai của mã của bạn, có vẻ như không cần sử dụng toán tử có điều kiện null sau GetMember vì phương thức này luôn trả về một mảng MemberInfo và không bao giờ trả về null. Và đối với tôi, có vẻ như tốt hơn là sử dụng FirstOrDefault thay vì chỉ First. Sau đó, việc sử dụng toán tử có điều kiện null sau FirstOrDefault sẽ được nhìn thấy nhất quán.
Alex34758

28

Nếu bạn đang sử dụng MVC 5.1 trở lên, có một cách đơn giản và rõ ràng hơn: chỉ cần sử dụng chú thích dữ liệu (từ System.ComponentModel.DataAnnotationskhông gian tên) như bên dưới:

public enum Color
{
    [Display(Name = "Dark red")]
    DarkRed,
    [Display(Name = "Very dark red")]
    VeryDarkRed,
    [Display(Name = "Red or just black?")]
    ReallyDarkRed
}

Và trong chế độ xem, chỉ cần đặt nó vào trình trợ giúp html thích hợp:

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

@Seg sắcFault tại sao? Bạn có thể mô tả vấn đề của bạn? Bạn sử dụng phiên bản .NET / MVC nào? Bạn có lỗi gì? Xin hãy cụ thể hơn.
1_ bọ

6
Bởi vì nó chỉ hoạt động cho Dropdowns, không phải nơi nào khác.
Lỗi phân đoạn

2
Dường như không tồn tại trong lõi .net
Lonefish

3
lõi .net sử dụng Html.GetEnumSelectList (typeof (YourEnum)) @Lonefish
Patrick Mcvay

2
nếu chúng ta muốn sử dụng @ Html.DisplayFor (yourEnumField), chúng ta có thể đặt Enum.cshtml trong thư mục DisplayTem mẫu (trong thư mục dùng chung). trong tập tin này chúng ta chỉ cần đặt 2 dòng. đầu tiên là: "@model Enum" thứ hai là: "@GetDisplayName (Model)." phương thức GetDisplayName cần phải có trong @Bernoulli CNTT answare
Nhà phát triển

11

Bạn có thể sử dụng Phương thức Type.GetMember , sau đó lấy thông tin thuộc tính bằng phản chiếu:

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

Có một vài bài viết tương tự ở đây:

Lấy thuộc tính của giá trị Enum

Làm cách nào để hiển thị MVC3 Hiển thị giá trị của Thuộc tính hiển thị của Enum?


8

Dựa trên câu trả lời tuyệt vời của Todd được xây dựng dựa trên câu trả lời tuyệt vời của Aydin , đây là một phương pháp mở rộng chung không yêu cầu bất kỳ tham số loại nào.

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

Tôi cần điều này cho dự án của mình bởi vì một cái gì đó giống như đoạn mã dưới đây, nơi mà không phải mọi thành viên của enum đều có DisplayAttribute, không hoạt động với giải pháp của Todd:

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

Nếu đây là một giải pháp phức tạp cho một vấn đề đơn giản, xin vui lòng cho tôi biết, nhưng đây là cách khắc phục tôi đã sử dụng.


6
<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>

Không hoạt động: / Tôi đang gặp lỗiInvalidOperationException: Templates can be used only with field access, property access, single-dimension array index, or single-parameter custom indexer expressions.
Muflix

6

Tôi có hai giải pháp cho câu hỏi này.

  1. Giải pháp đầu tiên là lấy tên hiển thị từ enum.
public enum CourseLocationTypes
{
    [Display(Name = "On Campus")]
    OnCampus,
    [Display(Name = "Online")]
    Online,
    [Display(Name = "Both")]
    Both
}

public static string DisplayName(this Enum value)
{
    Type enumType = value.GetType();
    string enumValue = Enum.GetName(enumType, value);
    MemberInfo member = enumType.GetMember(enumValue)[0];

    object[] attrs = member.GetCustomAttributes(typeof(DisplayAttribute), false);
    string outString = ((DisplayAttribute)attrs[0]).Name;

    if (((DisplayAttribute)attrs[0]).ResourceType != null)
    {
        outString = ((DisplayAttribute)attrs[0]).GetName();
    }

    return outString;
}
<h3 class="product-title white">@Model.CourseLocationType.DisplayName()</h3>
  1. Giải pháp thứ hai là lấy tên hiển thị từ tên enum nhưng nó sẽ được phân tách bằng ngôn ngữ của nhà phát triển, nó được gọi là bản vá.
public static string SplitOnCapitals(this string text)
{
        var r = new Regex(@"
            (?<=[A-Z])(?=[A-Z][a-z]) |
             (?<=[^A-Z])(?=[A-Z]) |
             (?<=[A-Za-z])(?=[^A-Za-z])", RegexOptions.IgnorePatternWhitespace);

        return r.Replace(text, " ");
}
 <div class="widget-box pt-0">
     @foreach (var item in Enum.GetNames(typeof(CourseLocationType)))
     {
         <label class="pr-2 pt-1">
             @Html.RadioButtonFor(x => x.CourseLocationType, item, new { type = "radio", @class = "iCheckBox control-label" })&nbsp; @item.SplitOnCapitals()
         </label>
     }
     @Html.ValidationMessageFor(x => x.CourseLocationType)
 </div>

5

Đối với ASP.Net Core 3.0, điều này hiệu quả với tôi (tín dụng cho những người trả lời trước).

Lớp Enum của tôi:

using System;
using System.Linq;
using System.ComponentModel.DataAnnotations;
using System.Reflection;

public class Enums
{
    public enum Duration
    { 
        [Display(Name = "1 Hour")]
        OneHour,
        [Display(Name = "1 Day")]
        OneDay
    }

    // Helper method to display the name of the enum values.
    public static string GetDisplayName(Enum value)
    {
        return value.GetType()?
       .GetMember(value.ToString())?.First()?
       .GetCustomAttribute<DisplayAttribute>()?
       .Name;
    }
}

Lớp mẫu của tôi

public class MyViewModel
{
    public Duration Duration { get; set; }
}

Một ví dụ về chế độ xem dao cạo hiển thị nhãn và danh sách thả xuống. Lưu ý danh sách thả xuống không yêu cầu phương thức trợ giúp:

@model IEnumerable<MyViewModel> 

@foreach (var item in Model)
{
    <label asp-for="@item.Duration">@Enums.GetDisplayName(item.Duration)</label>
    <div class="form-group">
        <label asp-for="@item.Duration" class="control-label">Select Duration</label>
        <select asp-for="@item.Duration" class="form-control"
            asp-items="Html.GetEnumSelectList<Enums.Duration>()">
        </select>
    </div>
}

Tôi sẽ thêm một kiểm tra vào chuỗi trả về phương thức GetDisplayName.IsNullOrEmpty (retVal)? enumValue.ToString (): retVal;
Sniipe

4

Bạn cần sử dụng một chút sự phản chiếu để truy cập thuộc tính đó:

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;

Tôi khuyên bạn nên gói phương thức này trong một phương thức mở rộng hoặc thực hiện điều này trong một mô hình xem.


4

Với lõi 2.1,

public static string GetDisplayName(Enum enumValue)
{
  return enumValue.GetType()?
 .GetMember(enumValue.ToString())?[0]?
 .GetCustomAttribute<DisplayAttribute>()?
 .Name;
}

4

kết hợp tất cả các trường hợp cạnh với nhau từ phía trên:

  • enum thành viên với tên thành viên cơ sở ( Equals, ToString)
  • Displaythuộc tính tùy chọn

đây là mã của tôi:

public enum Enum
{
    [Display(Name = "What a weird name!")]
    ToString,

    Equals
}

public static class EnumHelpers
{
    public static string GetDisplayName(this Enum enumValue)
    {
        var enumType = enumValue.GetType();

        return enumType
                .GetMember(enumValue.ToString())
                .Where(x => x.MemberType == MemberTypes.Field && ((FieldInfo)x).FieldType == enumType)
                .First()
                .GetCustomAttribute<DisplayAttribute>()?.Name ?? enumValue.ToString();
    }
}

void Main()
{
    Assert.Equals("What a weird name!", Enum.ToString.GetDisplayName());
    Assert.Equals("Equals", Enum.Equals.GetDisplayName());
}

Giải pháp tốt đẹp xử lý thuộc tính Display tùy chọn. Cảm ơn!
Wellspring

3

Tôi rất tiếc phải làm điều này, nhưng tôi không thể sử dụng bất kỳ câu trả lời nào khác và không có thời gian để đưa ra ý kiến ​​trong các bình luận.

Sử dụng cú pháp C # 6.

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

2

Xây dựng thêm về câu trả lời của Aydin và Todd, đây là một phương pháp mở rộng cũng cho phép bạn lấy tên từ tệp tài nguyên

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

và sử dụng nó như

public enum Season 
{
    [Display(ResourceType = typeof(Resource), Name = Season_Summer")]
    Summer
}

Tôi đang cố gắng để làm việc này cho dự án của mình nhưng tôi gặp lỗi với "Trình quản lý tài nguyên mới (tài nguyên) .GetString (tên);" hàng. Tôi đã hỏi một câu hỏi ( stackoverflow.com/questions/31319251/ mài ) và tôi đã được gửi đến đây. Khi tôi xem "ResourceManager (resource)" trong khi chạy, nó sẽ trả về "Resources.Enums.resource". Mọi sự trợ giúp sẽ rất được trân trọng. Cảm ơn bạn!
Karinne

Đã cập nhật mã để xử lý tốt hơn null khi bạn không đặt Tên hiển thị cho một số giá trị enum - có thể giúp
Peter Kerr

Điều đó vẫn không hiệu quả. Tôi đã cập nhật câu hỏi của mình trên stackoverflow.com/questions/31319251/ với thông báo lỗi. Cảm ơn đã giúp đỡ!
Karinne

1

Tôi muốn đóng góp với phần mở rộng enum GetDisplayName phụ thuộc vào văn hóa. Hy vọng điều này sẽ hữu ích cho bất cứ ai googling câu trả lời này như tôi trước đây:

Cách "nổi bật" như Aydin AdnTodd đã đề cập:

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

Cách "phụ thuộc vào văn hóa":

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

1

Cập nhật 2020: Phiên bản cập nhật của chức năng được cung cấp bởi nhiều người trong chuỗi này nhưng giờ đây cho C # 7.3 trở đi:

Bây giờ bạn có thể hạn chế các phương thức chung cho các kiểu enums để bạn có thể viết một phần mở rộng phương thức duy nhất để sử dụng nó với tất cả các enum của bạn như thế này:

Phương pháp mở rộng chung:

public static string ATexto<T>(this T enumeración) where T : struct, Enum {
    var tipo = enumeración.GetType();
    return tipo.GetMember(enumeración.ToString())
    .Where(x => x.MemberType == MemberTypes.Field && ((FieldInfo)x).FieldType == tipo).First()
    .GetCustomAttribute<DisplayAttribute>()?.Name ?? enumeración.ToString();
} 

Enum:

public enum TipoImpuesto { 
IVA, INC, [Display(Name = "IVA e INC")]IVAeINC, [Display(Name = "No aplica")]NoAplica };

Làm thế nào để sử dụng nó:

var tipoImpuesto = TipoImpuesto.IVAeINC;
var textoTipoImpuesto = tipoImpuesto.ATexto(); // Prints "IVA e INC".

Tiền thưởng, Enums với Cờ: Nếu bạn đang xử lý các enum bình thường thì hàm trên là đủ, nhưng nếu bất kỳ enum nào của bạn có thể lấy nhiều giá trị với việc sử dụng cờ thì bạn sẽ cần sửa đổi nó như thế này (Mã này sử dụng C # 8 đặc trưng):

    public static string ATexto<T>(this T enumeración) where T : struct, Enum {

        var tipo = enumeración.GetType();
        var textoDirecto = enumeración.ToString();

        string obtenerTexto(string textoDirecto) => tipo.GetMember(textoDirecto)
            .Where(x => x.MemberType == MemberTypes.Field && ((FieldInfo)x).FieldType == tipo)
            .First().GetCustomAttribute<DisplayAttribute>()?.Name ?? textoDirecto;

        if (textoDirecto.Contains(", ")) {

            var texto = new StringBuilder();
            foreach (var textoDirectoAux in textoDirecto.Split(", ")) {
                texto.Append($"{obtenerTexto(textoDirectoAux)}, ");
            }
            return texto.ToString()[0..^2];

        } else {
            return obtenerTexto(textoDirecto);
        }

    } 

Enum với cờ:

[Flags] public enum TipoContribuyente {
    [Display(Name = "Común")] Común = 1, 
    [Display(Name = "Gran Contribuyente")] GranContribuyente = 2, 
    Autorretenedor = 4, 
    [Display(Name = "Retenedor de IVA")] RetenedorIVA = 8, 
    [Display(Name = "Régimen Simple")] RégimenSimple = 16 } 

Làm thế nào để sử dụng nó:

var tipoContribuyente = TipoContribuyente.RetenedorIVA | TipoContribuyente.GranContribuyente;
var textoAux = tipoContribuyente.ATexto(); // Prints "Gran Contribuyente, Retenedor de IVA".

0

Dựa trên các câu trả lời trước đây, tôi đã tạo người trợ giúp thoải mái này để hỗ trợ tất cả các thuộc tính DisplayAttribution theo cách dễ đọc:

public static class EnumExtensions
    {
        public static DisplayAttributeValues GetDisplayAttributeValues(this Enum enumValue)
        {
            var displayAttribute = enumValue.GetType().GetMember(enumValue.ToString()).First().GetCustomAttribute<DisplayAttribute>();

            return new DisplayAttributeValues(enumValue, displayAttribute);
        }

        public sealed class DisplayAttributeValues
        {
            private readonly Enum enumValue;
            private readonly DisplayAttribute displayAttribute;

            public DisplayAttributeValues(Enum enumValue, DisplayAttribute displayAttribute)
            {
                this.enumValue = enumValue;
                this.displayAttribute = displayAttribute;
            }

            public bool? AutoGenerateField => this.displayAttribute?.GetAutoGenerateField();
            public bool? AutoGenerateFilter => this.displayAttribute?.GetAutoGenerateFilter();
            public int? Order => this.displayAttribute?.GetOrder();
            public string Description => this.displayAttribute != null ? this.displayAttribute.GetDescription() : string.Empty;
            public string GroupName => this.displayAttribute != null ? this.displayAttribute.GetGroupName() : string.Empty;
            public string Name => this.displayAttribute != null ? this.displayAttribute.GetName() : this.enumValue.ToString();
            public string Prompt => this.displayAttribute != null ? this.displayAttribute.GetPrompt() : string.Empty;
            public string ShortName => this.displayAttribute != null ? this.displayAttribute.GetShortName() : this.enumValue.ToString();
        }
    }

0

Tôi đã thử làm điều này như một chỉnh sửa nhưng nó đã bị từ chối; Tôi không thể hiểu tại sao.

Ở trên sẽ đưa ra một ngoại lệ nếu bạn gọi nó bằng Enum có kết hợp các thuộc tính tùy chỉnh và các mục đơn giản, ví dụ:

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

Vì vậy, tôi đã sửa đổi mã từng chút một để kiểm tra các thuộc tính tùy chỉnh trước khi thử truy cập chúng và sử dụng tên nếu không tìm thấy.

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

0

Sử dụng MVC5 bạn có thể sử dụng:

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
}

sau đó nếu bạn muốn tạo bộ chọn thả xuống, bạn có thể sử dụng:

@Html.EnumDropdownListFor(expression: model => model.PromotionSelector, optionLabel: "Select") 
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.