วิธีรับแอตทริบิวต์ชื่อที่แสดงของสมาชิก 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.