วิธีรับแอตทริบิวต์ชื่อที่แสดงของสมาชิก Enum ผ่านรหัสมีดโกน MVC


211

ฉันมีสถานที่ให้บริการในแบบจำลองของฉันที่เรียกว่า "การส่งเสริมการขาย" ที่ประเภทของมันคือการตั้งค่าสถานะ enum ที่เรียกว่า "UserPromotion" สมาชิกของ enum ของฉันมีชุดการแสดงผลดังนี้:

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

ตอนนี้ฉันต้องการที่จะสามารถสร้างพูด ul ในมุมมองของฉันเพื่อแสดงค่าที่เลือกของคุณสมบัติ "โปรโมชั่น" ของฉัน นี่คือสิ่งที่ฉันได้ทำไปแล้ว แต่ปัญหาคือว่าฉันจะได้รับชื่อที่แสดงที่นี่ได้อย่างไร

<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 รองรับแอตทริบิวต์ DisplayName บน enums
— Bart Calixto

10
System.ComponentModel.DataAnnotations.DisplayAttributeการจะมีความชัดเจนมากยิ่งขึ้นเท่านั้น System.ComponentModel.DisplayNameAttributeไม่
— kamranicus

1
สิ่งนี้รวมถึงการใช้การสะท้อนดังนั้นจึงส่งผลกระทบต่อประสิทธิภาพหรือไม่ เพราะนี่จะเรียกว่าเวลามาก
— Nico

คำตอบ:


182

UPDATE

วิธีแก้ปัญหาแรกมุ่งเน้นไปที่การแสดงชื่อจาก enum รหัสด้านล่างควรเป็นวิธีแก้ไขปัญหาของคุณอย่างแน่นอน

คุณสามารถใช้คลาสตัวช่วยนี้สำหรับ 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();
    }
}

และจากนั้นคุณสามารถใช้มันในมุมมองของคุณดังต่อไปนี้:

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

หวังว่ามันจะช่วย! :)


8
คำตอบทั้งหมดใช้.ToStringแต่จากstackoverflow.com/q/483794/179311มันบอกว่าจะใช้Enum.GetNameแทน
— bradlis7

value.GetType () GetField (value.ToString ()) เป็นสิ่งที่ฉันกำลังมองหา!
— cdie

คำตอบนี้ใช้ได้กับการตรวจสอบ null ที่เพิ่มเข้ามา แต่ถ้าคุณไม่ได้ใช้ dotfuscation คำตอบที่stackoverflow.com/a/4412730/852806ดูเหมือนง่ายกว่า
— HockeyJ

5
ในGetDisplayValueครั้งแรกคุณควรทดสอบdescriptionAttributes == nullก่อนที่จะพยายามเข้าถึงอาเรย์: descriptionAttributes[0]. มิฉะนั้นคุณอาจเพิ่มข้อยกเว้นและบรรทัดด้านล่างที่คุณตรวจสอบ null จะไม่เป็นจริง
— Robert S.

ฉันขอแนะนำให้ผู้เยาว์เปลี่ยนแปลง: public static IList <T> GetValues ​​(ค่า Enum) อาจเป็น public static IList <T> GetValues ​​(ค่า T) EnumHelper <T> ถึง => คลาสสแตติกสาธารณะ EnumHelper <T> โดยที่ T: struct, IConvertible อาจเป็นตัวสร้างแบบคงที่? EnumHelper คงที่ () {ถ้า (! typeof (T) .IsEnum) {โยน ArgumentException ใหม่ ("T ต้องเป็นประเภทที่ระบุ"); }}
— Tom

172

หนึ่งซับ - ไวยากรณ์ได้อย่างคล่องแคล่ว

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

ตัวอย่าง

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

เอาท์พุต

ฤดูกาลไหน
มันคือหน้าร้อน


2
ไม่มีคำจำกัดความของ GetCustomAttribute
— Tito

3
@Tito ตรวจสอบให้แน่ใจว่าโครงการของคุณกำหนดเป้าหมาย.NET Framework 4.5และคุณได้รวมเนมสเปซต่อไปนี้ไว้ด้วยSystem.Net System.ComponentModel.DataAnnotations
— Aydin

8
ใช้ System.Reflection ใช้ System.ComponentModel.DataAnnotations; เป็นสิ่งจำเป็นสำหรับฉัน
— ผิด Lolwut

1
มันเป็นแผนการประชุมที่แย่ขนาดไหน!
— อยากรู้อยากเห็นบอย

@curiousBoy เป็นวิธีGetAttribute<TAttribute>การตั้งชื่อที่น่ากลัวอย่างไร มันดึงคุณลักษณะที่คุณระบุและใช้ท่อปาสคาลเป็นวิธีการสาธารณะควรทั้งหมด
— Aydin

137

อาคารในคำตอบที่ดีเอดินของที่นี่เป็นวิธีขยายที่ไม่ต้องใช้พารามิเตอร์ชนิดใด ๆ

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 () ควรใช้แทนคุณสมบัติชื่อ สิ่งนี้ทำให้มั่นใจได้ว่าสตริงที่แปลเป็นภาษาท้องถิ่นจะถูกส่งคืนถ้าใช้คุณสมบัติ

ตัวอย่าง

หากต้องการใช้เพียงอ้างอิงค่า enum ในมุมมองของคุณ

@{
    UserPromotion promo = UserPromotion.SendJobOffersByMail;
}

Promotion: @promo.GetDisplayName()

เอาท์พุต

โปรโมชั่น: ส่งข้อเสนองานทางไปรษณีย์


4
ใช้เพื่อเพิ่มเนมสเปซต่อไปนี้: using System; ใช้ System.ComponentModel.DataAnnotations; ใช้ System.Linq; ใช้ System.Reflection
— Peter Kerr

โซลูชันที่ลื่นไหล แต่ฉันได้รับ {"เทมเพลตสามารถใช้ได้เฉพาะกับการเข้าถึงฟิลด์การเข้าถึงคุณสมบัติดัชนีอาเรย์มิติเดียวหรือนิพจน์ตัวทำดัชนีที่กำหนดเองพารามิเตอร์เดียว"}
— Casey Crookston

ดูคำตอบ SO อื่น ๆ สำหรับข้อความแสดงข้อผิดพลาดนี้ (ฉันไม่คุ้นเคย) ปรากฏว่าคุณอาจใช้สิ่งนี้จากภายในวิธีการ Html helper (เช่น@Html.DisplayFor(m => m.myEnum.GetDisplayName())ที่ใช้ไม่ได้เพราะพวกเขาคาดหวังว่านิพจน์ที่ประเมินแล้วจะให้คุณสมบัติ หรือสิ่งที่คล้ายกันคุณควรใช้ค่า enum เปลือยตามตัวอย่างด้านบน
— ทอดด์

7
ฉันได้เพิ่มการตรวจสอบการอ้างอิงแบบ null ไปยังผลลัพธ์ของGetCustomAttribute<DisplayAttribute>()เพราะสำหรับ Enums บางอันบางทีนี่อาจไม่ปรากฏ มันจะกลับไปenumValue.ToString()หาก DisplayAttribute ไม่มีอยู่
— H Dog

1
ฉันใช้สิ่งนี้เพื่อสร้างสิ่งList<SelectListItem>ที่ Enum บรรจุด้วยDisplayAttribute.Nameบันทึกย่อแต่ละรายการซึ่งทำงานได้อย่างสมบูรณ์แบบขอบคุณมาก !! 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() }); }
— กระโดด

61

จากคำตอบของ Aydinฉันขอแนะนำให้ใช้งาน "ซ้ำซ้อน" น้อยลง (เพราะเราสามารถรับค่าTypeจากEnumตัวมันเองได้ง่ายแทนที่จะให้มันเป็นพารามิเตอร์😉:

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

แก้ไข (ตามความคิดเห็น @Vahagn Nahapetyan)

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

ตอนนี้เราสามารถใช้มันสะอาดด้วยวิธีนี้:

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

ซึ่งส่งผลให้

"ความฝัน"


1
คำตอบที่ง่ายที่สุดและง่ายที่สุด ขอบคุณ!
— Casey Crookston

คุณควรระวังด้วย. First () สิ่งนี้จะทำให้เกิดข้อยกเว้นตัวอย่างเช่นถ้าชื่อ enum ของคุณคือ "Equals"
— Vahagn Nahapetyan

ฉันเข้าใจ "อันตราย" กับ First () ในกรณีนี้ดูเหมือนว่าจะไม่มีปัญหา เพราะมันเป็นวิธีการขยายที่thisจะต้องมีค่า Enum ที่ถูกต้อง (ไม่เป็นโมฆะ) มิฉะนั้นการโทรด้วยวิธีนี้จะใช้วิธีโยนแล้ว (ซึ่งเป็นความรับผิดชอบของรหัสการโทร) สิ่งนี้ทำให้GetType()แน่ใจได้ว่าจะให้ประเภท Enum ที่ถูกต้องซึ่งenumvalueแน่นอนว่าจะเป็นสมาชิก แต่ GetCustomAttribute อาจส่งคืนค่า Null ดังนั้นฉันได้จัดเตรียมวิธีการส่งคืนค่า Null รุ่นที่ไม่พิเศษเมื่อสายโซ่ของวิธีการเรียกใช้มีค่า Null ที่ใดที่หนึ่ง ขอบคุณ!
— Bernoulli ไอที

1
สำหรับตัวแปรที่สองของรหัสดูเหมือนว่าไม่จำเป็นต้องใช้ตัวดำเนินการ null ตามเงื่อนไขหลังจาก GetMember เนื่องจากวิธีนี้จะส่งคืนอาร์เรย์ MemberInfo เสมอและจะไม่ส่งคืน null และสำหรับฉันดูเหมือนว่าจะดีกว่าถ้าใช้ FirstOrDefault แทนที่จะเป็น First จากนั้นการใช้โอเปอเรเตอร์ที่มีเงื่อนไขหลังจาก FirstOrDefault จะเห็นอย่างสม่ำเสมอ
— Alex34758

28

หากคุณใช้ MVC 5.1 ขึ้นไปวิธีที่ง่ายกว่าและชัดเจนกว่า: เพียงใช้คำอธิบายประกอบข้อมูล (จากSystem.ComponentModel.DataAnnotationsเนมสเปซ) เช่นด้านล่าง:

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

และในมุมมองเพียงใส่ลงในตัวช่วย html ที่เหมาะสม:

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

@SegmentationFault เพราะเหตุใด คุณอธิบายปัญหาของคุณได้ไหม คุณใช้. NET / MVC รุ่นใด คุณมีข้อผิดพลาดอะไร กรุณาเจาะจงมากขึ้น
— 1_bug

6
เพราะมันใช้งานได้สำหรับดรอปดาวน์เท่านั้นไม่ใช่ที่อื่น
— การแบ่งกลุ่มความผิดพลาด

2
ดูเหมือนจะไม่มีอยู่ใน. net core
— Lonefish

3
.net core ใช้ Html.GetEnumSelectList (typeof (YourEnum)) @Lonefish
— Patrick Mcvay

2
ถ้าเราต้องการใช้ @ Html.DisplayFor (yourEnumField) เราสามารถใส่ Enum.cshtml ในไดเรกทอรี DisplayTemplates (ในไดเรกทอรีที่ใช้ร่วมกัน) ในไฟล์นี้เราต้องใส่แค่ 2 บรรทัด ตัวแรกคือ: "@model Enum" ตัวที่สองคือ: "@GetDisplayName (Model)" วิธี GetDisplayName ต้องเป็นใน @Bernoulli IT answare
— นักพัฒนา

11

คุณสามารถใช้วิธี Type.GetMemberจากนั้นรับข้อมูลคุณลักษณะโดยใช้การสะท้อน:

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

มีโพสต์ที่คล้ายกันอยู่สองสามข้อที่นี่:

รับคุณลักษณะของค่าของ Enum

วิธีการทำให้ MVC3 DisplayFor แสดงค่าของแอตทริบิวต์การแสดงผลของ Enum


8

การสร้างคำตอบที่ยอดเยี่ยมของทอดด์ซึ่งสร้างจากคำตอบที่ยอดเยี่ยมของ Aydinนี่เป็นวิธีการขยายทั่วไปที่ไม่ต้องการพารามิเตอร์ประเภทใด ๆ

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

ฉันต้องการสิ่งนี้สำหรับโครงการของฉันเพราะบางอย่างเช่นโค้ดด้านล่างซึ่งไม่ใช่สมาชิกของ enum ทุกคนที่มี a DisplayAttributeไม่ทำงานกับโซลูชันของทอดด์:

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

หากนี่เป็นวิธีแก้ปัญหาที่ซับซ้อนสำหรับปัญหาอย่างง่ายโปรดแจ้งให้เราทราบ แต่นี่เป็นการแก้ไขที่ฉันใช้


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>

ไม่ทำงาน: / ฉันได้รับข้อผิดพลาดInvalidOperationException: Templates can be used only with field access, property access, single-dimension array index, or single-parameter custom indexer expressions.
— Muflix

6

ฉันมีคำตอบสองข้อสำหรับคำถามนี้

  1. วิธีแรกคือการรับชื่อที่แสดงจาก 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. วิธีที่สองคือการรับชื่อที่แสดงจากชื่อ enum แต่นั่นจะเป็นการแบ่ง enum ในภาษาของนักพัฒนามันเรียกว่าแพทช์
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

สำหรับ ASP.Net Core 3.0 สิ่งนี้ใช้ได้กับฉัน (ให้เครดิตกับผู้ตอบก่อนหน้านี้)

คลาส Enum ของฉัน:

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

คลาสโมเดลมุมมองของฉัน:

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

ตัวอย่างของมุมมองมีดโกนที่แสดงเลเบลและรายการดร็อปดาวน์ แจ้งให้ทราบว่ารายการแบบหล่นลงไม่จำเป็นต้องมีวิธีช่วย:

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

ฉันจะเพิ่มการตรวจสอบใน GetDisplayName วิธีการส่งกลับสตริงสตริง IsNullOrEmpty (retVal)? enumValue.ToString (): retVal;
— Sniipe

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;

ฉันขอแนะนำให้ห่อวิธีนี้ในวิธีการขยายหรือดำเนินการในรูปแบบมุมมอง


4

ด้วย Core 2.1,

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

4

รวมขอบกรณีทั้งหมดเข้าด้วยกันจากด้านบน:

  • enum สมาชิกที่มีชื่อสมาชิกวัตถุฐาน ( Equals,ToString )
  • Displayแอตทริบิวต์ตัวเลือก

นี่คือรหัสของฉัน:

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

โซลูชันที่ดีที่จัดการแอตทริบิวต์ Display ที่เป็นตัวเลือก ขอบคุณ!
— Wellspring

3

ฉันขอโทษที่ทำเช่นนี้ แต่ฉันไม่สามารถใช้คำตอบอื่น ๆ ตามที่เป็นอยู่และไม่มีเวลาที่จะทำตามความคิดเห็น

ใช้ไวยากรณ์ 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

สร้างเพิ่มเติมจากคำตอบของ Aydin และทอดด์นี่คือวิธีส่วนขยายที่ช่วยให้คุณได้รับชื่อจากไฟล์ทรัพยากร

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

และใช้มันเหมือน

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

ฉันพยายามทำให้มันใช้งานได้สำหรับโครงการของฉัน แต่ฉันพบข้อผิดพลาดกับ "ResourceManager ใหม่ (ทรัพยากร) .GetString (ชื่อ)" ไลน์. ฉันได้ถามคำถาม ( stackoverflow.com/questions/31319251/ … ) และฉันถูกส่งไปที่นี่ เมื่อฉันดู "ResourceManager (ทรัพยากร)" ในขณะที่เรียกใช้มันจะส่งคืน "Resources.Enums.resource" ความช่วยเหลือใด ๆ ที่จะได้รับการชื่นชมอย่างมาก. ขอบคุณ!
— Karinne

อัปเดตรหัสเพื่อจัดการ nulls ได้ดีขึ้นเมื่อคุณไม่ได้ตั้งชื่อที่แสดงสำหรับค่า enum บางรายการ - อาจช่วยได้
— Peter Kerr

ยังไม่ได้ผล ฉันอัปเดตคำถามของฉันในstackoverflow.com/questions/31319251/…พร้อมข้อความแสดงข้อผิดพลาด ขอบคุณสำหรับความช่วยเหลือ!
— Karinne

1

ฉันต้องการมีส่วนร่วมกับส่วนขยาย enum GetDisplayName ที่ขึ้นกับวัฒนธรรม หวังว่านี้จะเป็นประโยชน์สำหรับทุกคน googling คำตอบนี้เหมือนฉันก่อนหน้านี้:

วิธี "รูปแบบ" ตามที่Aydin AdnและToddกล่าวถึง

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

วิธี "ขึ้นอยู่กับวัฒนธรรม":

    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

2020 Update:ฟังก์ชั่นเวอร์ชั่นที่ได้รับการอัปเดตของหลาย ๆ อย่างในเธรดนี้ แต่ตอนนี้สำหรับ C # 7.3 เป็นต้นไป:

ตอนนี้คุณสามารถ จำกัด วิธีการทั่วไปให้กับประเภท enums เพื่อให้คุณสามารถเขียนส่วนขยายวิธีการเดียวเพื่อใช้กับ enums ทั้งหมดของคุณเช่นนี้:

วิธีการขยายทั่วไป:

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

วิธีใช้:

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

โบนัส, Enums with Flags:หากคุณจัดการกับEnumsปกติฟังก์ชั่นด้านบนก็เพียงพอแล้ว แต่ถ้าEnumsใด ๆ ของคุณสามารถรับค่าหลาย ๆ ค่าได้ด้วยการใช้ค่าสถานะคุณจะต้องแก้ไขเช่นนี้ (รหัสนี้ใช้ C # 8 มี):

    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 ด้วยธง:

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

วิธีใช้:

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

0

จากคำตอบก่อนหน้านี้ฉันได้สร้างผู้ช่วยที่สะดวกสบายนี้เพื่อสนับสนุนคุณสมบัติ DisplayAttribute ทั้งหมดด้วยวิธีที่อ่านได้:

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

ฉันลองทำสิ่งนี้เป็นการแก้ไข แต่มันถูกปฏิเสธ ฉันไม่เห็นสาเหตุ

ด้านบนจะมีข้อยกเว้นหากคุณเรียกใช้ด้วย Enum ที่มีการผสมผสานของแอตทริบิวต์ที่กำหนดเองและรายการธรรมดาเช่น

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

ดังนั้นฉันจึงแก้ไขโค้ดเล็กน้อยเพื่อตรวจสอบแอตทริบิวต์ที่กำหนดเองก่อนที่จะพยายามเข้าถึงพวกเขาและใช้ชื่อหากไม่พบ

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

การใช้ MVC5 คุณสามารถใช้:

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
}

ถ้าคุณต้องการสร้างตัวเลือกแบบเลื่อนลงคุณสามารถใช้:

@Html.EnumDropdownListFor(expression: model => model.PromotionSelector, optionLabel: "Select") 
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.