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


483

ฉันต้องการทราบว่าเป็นไปได้ไหมที่จะรับคุณลักษณะของenumค่าและไม่ใช่ของenumตัวเอง? ตัวอย่างเช่นสมมติว่าฉันมีสิ่งต่อไปนี้enum:

using System.ComponentModel; // for DescriptionAttribute

enum FunkyAttributesEnum
{
    [Description("Name With Spaces1")]
    NameWithoutSpaces1,    
    [Description("Name With Spaces2")]
    NameWithoutSpaces2
}

สิ่งที่ฉันต้องการคือประเภท enum สร้าง 2-tuples ของค่า enum string และคำอธิบาย

คุณค่านั้นง่าย:

Array values = System.Enum.GetValues(typeof(FunkyAttributesEnum));
foreach (int value in values)
    Tuple.Value = Enum.GetName(typeof(FunkyAttributesEnum), value);

แต่ฉันจะรับค่าคุณลักษณะของคำอธิบายเพื่อเติมได้Tuple.Descอย่างไร ฉันสามารถคิดวิธีที่จะทำถ้าแอตทริบิวต์เป็นของenumตัวเอง enumแต่ฉันที่สูญเสียเป็นวิธีการที่จะได้รับจากค่าของ


จากอีกคำถามstackoverflow.com/questions/469287/…
finnw


2
เนมสเปซที่จำเป็นสำหรับคำอธิบายคือ System.ComponentModel
John M

คุณยังไม่สามารถใช้ System.ComponentModel และเพียงแค่ใช้ประเภทแอตทริบิวต์ของคุณเอง DescriptionAttributeมีจริงๆไม่มีอะไรทุกอย่างที่เกี่ยวกับการพิเศษ
jrh

โปรดดูที่ลิงค์นี้: stackoverflow.com/a/58954215/5576498
AminGolmahalle

คำตอบ:


482

สิ่งนี้ควรทำในสิ่งที่คุณต้องการ

var enumType = typeof(FunkyAttributesEnum);
var memberInfos = enumType.GetMember(FunkyAttributesEnum.NameWithoutSpaces1.ToString());
var enumValueMemberInfo = memberInfos.FirstOrDefault(m => m.DeclaringType == enumType);
var valueAttributes = 
      enumValueMemberInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
var description = ((DescriptionAttribute)valueAttributes[0]).Description;

10
เลือกใช้ type.GetFields (BindingFlags.Public | BindingFlags.Static) เพื่อรับ memInfos ทั้งหมดพร้อมกัน
TrueWill

4
ฉันต้องไปพิมพ์ (FunkyAttributesEnum) แต่นอกเหนือจากนั้นมันทำงานได้ดี ขอบคุณ
Greg Randall

@AlexK ฉันไม่เห็นคลาส Enum มีคุณสมบัติ NameWithoutSpaces1 FunkyAttributesEnum.NameWithoutSpaces1 มาจากไหน
อย่า

2
@ ดอนมันเป็นชื่อสมาชิก enum จากคำถามของ OP
MEMark

287

โค้ดส่วนนี้ควรให้วิธีการขยายเล็กน้อยกับ enum ใด ๆ ที่ช่วยให้คุณสามารถดึงแอตทริบิวต์ทั่วไปได้ ฉันเชื่อว่ามันแตกต่างจากฟังก์ชั่นแลมบ์ดาด้านบนเพราะมันใช้งานง่ายกว่าและเล็กน้อย - คุณต้องผ่านประเภททั่วไปเท่านั้น

public static class EnumHelper
{
    /// <summary>
    /// Gets an attribute on an enum field value
    /// </summary>
    /// <typeparam name="T">The type of the attribute you want to retrieve</typeparam>
    /// <param name="enumVal">The enum value</param>
    /// <returns>The attribute of type T that exists on the enum value</returns>
    /// <example><![CDATA[string desc = myEnumVariable.GetAttributeOfType<DescriptionAttribute>().Description;]]></example>
    public static T GetAttributeOfType<T>(this Enum enumVal) where T:System.Attribute
    {
        var type = enumVal.GetType();
        var memInfo = type.GetMember(enumVal.ToString());
        var attributes = memInfo[0].GetCustomAttributes(typeof(T), false);
        return (attributes.Length > 0) ? (T)attributes[0] : null;
    }
}

19
การใช้งานจะเป็น: string desc = myEnumVariable.GetAttributeOfType <DescriptionAttribute> () .Description;
แบรด Rem

2
ฉันชอบอันนี้มากกว่าสกอตต์เนื่องจากการใช้งานที่นี่สะอาดกว่า (พิมพ์น้อยลง) ดังนั้น +1 :)
nawfal

3
ถ้าไม่มีแอตทริบิวต์ที่มีอยู่นี้จะไม่โยนIndexOutOfRangeException?
Erik Philips

6
ควรใช้ type.GetMember (Enum.GetName (type, enumVal)) สำหรับ memInfo เป็น enumVal.ToString () อาจไม่น่าเชื่อถือสำหรับตำแหน่งที่ตั้งอื่น
หลินซ่งหยาง

2
อะไรคือจุดของการโทรGetCustomAttributes()แล้วรับองค์ประกอบแรกแทนการโทรGetCustomAttribute()?
tigrou

81

นี่เป็นการใช้งานทั่วไปโดยใช้แลมบ์ดาสำหรับการเลือก

public static Expected GetAttributeValue<T, Expected>(this Enum enumeration, Func<T, Expected> expression)
    where T : Attribute
{
    T attribute =
      enumeration
        .GetType()
        .GetMember(enumeration.ToString())
        .Where(member => member.MemberType == MemberTypes.Field)
        .FirstOrDefault()
        .GetCustomAttributes(typeof(T), false)
        .Cast<T>()
        .SingleOrDefault();

    if (attribute == null)
        return default(Expected);

    return expression(attribute);
}

เรียกว่าเป็นแบบนี้:

string description = targetLevel.GetAttributeValue<DescriptionAttribute, string>(x => x.Description);

4
มันเยี่ยมมาก เราต้องระวังถ้าค่าการแจกแจงที่ระบุเป็นการรวมกัน (อนุญาตโดยFlagsAttribute) ในกรณีนี้enumeration.GetType().GetMember(enumeration.ToString())[0]จะล้มเหลว
Remio

สั้นที่สุดที่คุณสามารถเขียน: value.GetType().GetField(value.ToString()).GetCustomAttributes(false).OfType<T>‌​().SingleOrDefault()แต่ต้องยอมรับวิธีที่ชัดเจนของคุณจะดีกว่า
nawfal

2
ฉันยังเพิ่ม GetDescription String แบบคงที่สาธารณะ (การแจงนับ Enum นี้) {return enumeration.GetAttributeValue <DescriptionAttribute, String> (x => x.Description); } วิธีนั้นเป็นเพียง targetLevel.GetDescription ();
MarkKGreenway

65

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

using System;
using System.ComponentModel;

public static class EnumExtensions {

    // This extension method is broken out so you can use a similar pattern with 
    // other MetaData elements in the future. This is your base method for each.
    public static T GetAttribute<T>(this Enum value) where T : Attribute {
        var type = value.GetType();
        var memberInfo = type.GetMember(value.ToString());
        var attributes = memberInfo[0].GetCustomAttributes(typeof(T), false);
        return attributes.Length > 0 
          ? (T)attributes[0]
          : null;
    }

    // This method creates a specific call to the above method, requesting the
    // Description MetaData attribute.
    public static string ToName(this Enum value) {
        var attribute = value.GetAttribute<DescriptionAttribute>();
        return attribute == null ? value.ToString() : attribute.Description;
    }

}

โซลูชันนี้สร้างวิธีการขยายคู่บน Enum วิธีแรกให้คุณใช้การสะท้อนเพื่อดึงข้อมูลคุณลักษณะที่เกี่ยวข้องกับค่าของคุณ การโทรที่สองจะดึงDescriptionAttributeและคืนสายนั้นโดยเฉพาะDescriptionคุ้มค่า

เป็นตัวอย่างให้พิจารณาใช้DescriptionAttributeคุณลักษณะจากSystem.ComponentModel

using System.ComponentModel;

public enum Days {
    [Description("Sunday")]
    Sun,
    [Description("Monday")]
    Mon,
    [Description("Tuesday")]
    Tue,
    [Description("Wednesday")]
    Wed,
    [Description("Thursday")]
    Thu,
    [Description("Friday")]
    Fri,
    [Description("Saturday")]
    Sat
}

หากต้องการใช้วิธีการส่วนขยายข้างต้นคุณเพียงแค่เรียกวิธีต่อไปนี้:

Console.WriteLine(Days.Mon.ToName());

หรือ

var day = Days.Mon;
Console.WriteLine(day.ToName());

ในบรรทัดสุดท้ายคุณหมายถึง "attribute.Description" หรือไม่ return attribute == null? value.ToString (): attribute.Description;
Jeson Martajaya

2
ฉันชอบโซลูชันนี้ แต่มีข้อผิดพลาดอยู่ในนั้น กระบวนการ GetAttribute วิธีการสันนิษฐานว่าค่า enum มีคุณลักษณะคำอธิบายและดังนั้นจะโยนข้อยกเว้นเมื่อความยาวของแอตทริบิวต์คือ 0 แทนที่แอตทริบิวต์ "return (T) [0];" ด้วย "return (attributes.Length> 0? (T) attribute [0]: null);"
Simon Gymer

@SimonGymer ขอบคุณสำหรับคำแนะนำ - ฉันได้อัปเดตตามนั้น :)
Troy Alford

38

นอกเหนือจากการตอบสนองของ AdamCrawfordฉันยังได้สร้างวิธีการขยายพิเศษเพิ่มเติมที่ดึงข้อมูลเพื่อให้ได้คำอธิบาย

public static string GetAttributeDescription(this Enum enumValue)
{
    var attribute = enumValue.GetAttributeOfType<DescriptionAttribute>();
    return attribute == null ? String.Empty : attribute.Description;
} 

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

string desc = myEnumVariable.GetAttributeOfType<DescriptionAttribute>().Description

หรือคุณสามารถเรียกวิธีการขยายได้ที่นี่เช่น:

string desc = myEnumVariable.GetAttributeDescription();

ซึ่งหวังว่าจะทำให้โค้ดของคุณอ่านง่ายขึ้นอีกเล็กน้อย


16

ซับได้อย่างคล่องแคล่ว ...

ที่นี่ฉันใช้DisplayAttributeซึ่งมีทั้งNameและDescriptionคุณสมบัติ

public static DisplayAttribute GetDisplayAttributesFrom(this Enum enumValue, Type enumType)
{
    return enumType.GetMember(enumValue.ToString())
                   .First()
                   .GetCustomAttribute<DisplayAttribute>();
}

ตัวอย่าง

public enum ModesOfTransport
{
    [Display(Name = "Driving",    Description = "Driving a car")]        Land,
    [Display(Name = "Flying",     Description = "Flying on a plane")]    Air,
    [Display(Name = "Sea cruise", Description = "Cruising on a dinghy")] Sea
}

void Main()
{
    ModesOfTransport TransportMode = ModesOfTransport.Sea;
    DisplayAttribute metadata = TransportMode.GetDisplayAttributesFrom(typeof(ModesOfTransport));
    Console.WriteLine("Name: {0} \nDescription: {1}", metadata.Name, metadata.Description);
}

เอาท์พุต

Name: Sea cruise 
Description: Cruising on a dinghy

2
ฉันใช้สิ่งนี้เช่นกันมันเป็นคำตอบที่สะอาดที่สุด! +1
Mafii

ดูเหมือนว่าจะมีประโยชน์มาก! ขอบคุณ
IRF

7

นี่คือรหัสสำหรับรับข้อมูลจากแอตทริบิวต์การแสดงผล มันใช้วิธีการทั่วไปเพื่อดึงคุณสมบัติ หากไม่พบคุณลักษณะจะแปลงค่า enum เป็นสตริงที่มีตัวแปลง pascal / camel เป็นตัวพิมพ์ใหญ่ (รับรหัสที่นี่ )

public static class EnumHelper
{
    // Get the Name value of the Display attribute if the   
    // enum has one, otherwise use the value converted to title case.  
    public static string GetDisplayName<TEnum>(this TEnum value)
        where TEnum : struct, IConvertible
    {
        var attr = value.GetAttributeOfType<TEnum, DisplayAttribute>();
        return attr == null ? value.ToString().ToSpacedTitleCase() : attr.Name;
    }

    // Get the ShortName value of the Display attribute if the   
    // enum has one, otherwise use the value converted to title case.  
    public static string GetDisplayShortName<TEnum>(this TEnum value)
        where TEnum : struct, IConvertible
    {
        var attr = value.GetAttributeOfType<TEnum, DisplayAttribute>();
        return attr == null ? value.ToString().ToSpacedTitleCase() : attr.ShortName;
    }

    /// <summary>
    /// Gets an attribute on an enum field value
    /// </summary>
    /// <typeparam name="TEnum">The enum type</typeparam>
    /// <typeparam name="T">The type of the attribute you want to retrieve</typeparam>
    /// <param name="value">The enum value</param>
    /// <returns>The attribute of type T that exists on the enum value</returns>
    private static T GetAttributeOfType<TEnum, T>(this TEnum value)
        where TEnum : struct, IConvertible
        where T : Attribute
    {

        return value.GetType()
                    .GetMember(value.ToString())
                    .First()
                    .GetCustomAttributes(false)
                    .OfType<T>()
                    .LastOrDefault();
    }
}

และนี่คือวิธีการขยายสำหรับสตริงสำหรับแปลงเป็นชื่อเรื่อง:

    /// <summary>
    /// Converts camel case or pascal case to separate words with title case
    /// </summary>
    /// <param name="s"></param>
    /// <returns></returns>
    public static string ToSpacedTitleCase(this string s)
    {
        //https://stackoverflow.com/a/155486/150342
        CultureInfo cultureInfo = Thread.CurrentThread.CurrentCulture;
        TextInfo textInfo = cultureInfo.TextInfo;
        return textInfo
           .ToTitleCase(Regex.Replace(s, 
                        "([a-z](?=[A-Z0-9])|[A-Z](?=[A-Z][a-z]))", "$1 "));
    }

4

ฉันใช้วิธีการขยายนี้เพื่อรับรายละเอียดจากค่า enum มันทำงานได้สำหรับ enums ทุกชนิด

public static class EnumExtension
{
    public static string ToDescription(this System.Enum value)
    {
        FieldInfo fi = value.GetType().GetField(value.ToString());
        var attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
        return attributes.Length > 0 ? attributes[0].Description : value.ToString();
    }
}

เวอร์ชันทั่วไปของโซลูชันเดียวกันได้รับการโพสต์แล้ว imo ดีกว่า
nawfal

4

รับพจนานุกรมจาก enum

public static IDictionary<string, int> ToDictionary(this Type enumType)
{
    return Enum.GetValues(enumType)
    .Cast<object>()
    .ToDictionary(v => ((Enum)v).ToEnumDescription(), k => (int)k); 
}

ตอนนี้เรียกสิ่งนี้ว่า ...

var dic = typeof(ActivityType).ToDictionary();

วิธีการ EnumDecription

public static string ToEnumDescription(this Enum en) //ext method
{
    Type type = en.GetType();
    MemberInfo[] memInfo = type.GetMember(en.ToString());
    if (memInfo != null && memInfo.Length > 0)
    {
        object[] attrs = memInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
        if (attrs != null && attrs.Length > 0)
            return ((DescriptionAttribute)attrs[0]).Description;
    }
    return en.ToString();
}

public enum ActivityType
{
    [Description("Drip Plan Email")]
    DripPlanEmail = 1,
    [Description("Modification")]
    Modification = 2,
    [Description("View")]
    View = 3,
    [Description("E-Alert Sent")]
    EAlertSent = 4,
    [Description("E-Alert View")]
    EAlertView = 5
}

3

นี่คือรุ่น .NET หลักของคำตอบ AdamCrawford โดยใช้System.Reflection.TypeExtensions ;

public static class EnumHelper
{
    /// <summary>
    /// Gets an attribute on an enum field value
    /// </summary>
    /// <typeparam name="T">The type of the attribute you want to retrieve</typeparam>
    /// <param name="enumVal">The enum value</param>
    /// <returns>The attribute of type T that exists on the enum value</returns>
    /// <example>string desc = myEnumVariable.GetAttributeOfType<DescriptionAttribute>().Description;</example>
    public static T GetAttributeOfType<T>(this Enum enumVal) where T : System.Attribute
    {
        var type = enumVal.GetType();
        var memInfo = type.GetMember(enumVal.ToString());
        IEnumerable<Attribute> attributes = memInfo[0].GetCustomAttributes(typeof(T), false);
        return (T)attributes?.ToArray()[0];
    }
}

ฉันไม่เชื่อ. NET Core (หรือมากกว่านั้นตอนนี้มาตรฐาน) มี GetMember ดังนั้นฉันไม่แน่ใจว่าจะใช้งานได้อย่างไร
Jeff

อยู่ใน System.Reflection.TypeExtensions ฉันได้แก้ไขคำตอบเพื่อแสดงรายการนี้
wonea

1
Gotcha ขอบคุณ ฉันคิดว่าอาจมีส่วนขยายบางส่วนที่เล่น
Jeff

3

การเพิ่มโซลูชันของฉันสำหรับ Net Framework และ NetCore

ฉันใช้สิ่งนี้สำหรับการปรับใช้ Net Framework ของฉัน:

public static class EnumerationExtension
{
    public static string Description( this Enum value )
    {
        // get attributes  
        var field = value.GetType().GetField( value.ToString() );
        var attributes = field.GetCustomAttributes( typeof( DescriptionAttribute ), false );

        // return description
        return attributes.Any() ? ( (DescriptionAttribute)attributes.ElementAt( 0 ) ).Description : "Description Not Found";
    }
}

สิ่งนี้ใช้ไม่ได้กับ NetCore ดังนั้นฉันจึงแก้ไขเพื่อทำสิ่งนี้:

public static class EnumerationExtension
{
    public static string Description( this Enum value )
    {
        // get attributes  
        var field = value.GetType().GetField( value.ToString() );
        var attributes = field.GetCustomAttributes( false );

        // Description is in a hidden Attribute class called DisplayAttribute
        // Not to be confused with DisplayNameAttribute
        dynamic displayAttribute = null;

        if (attributes.Any())
        {
            displayAttribute = attributes.ElementAt( 0 );
        }

        // return description
        return displayAttribute?.Description ?? "Description Not Found";
    }
}

ตัวอย่างการแจงนับ:

public enum ExportTypes
{
    [Display( Name = "csv", Description = "text/csv" )]
    CSV = 0
}

ตัวอย่างการใช้งานสำหรับการเพิ่มคงที่:

var myDescription = myEnum.Description();

2

การใช้ประโยชน์จากคุณสมบัติภาษา C # ใหม่บางอย่างคุณสามารถลดจำนวนบรรทัด:

public static TAttribute GetEnumAttribute<TAttribute>(this Enum enumVal) where TAttribute : Attribute
{
    var memberInfo = enumVal.GetType().GetMember(enumVal.ToString());
    return memberInfo[0].GetCustomAttributes(typeof(TAttribute), false).OfType<TAttribute>().FirstOrDefault();
}

public static string GetEnumDescription(this Enum enumValue) => enumValue.GetEnumAttribute<DescriptionAttribute>()?.Description ?? enumValue.ToString();

2

ฉันคำตอบนี้เพื่อตั้งค่ากล่องคำสั่งผสมจากคุณลักษณะ enum ที่ยอดเยี่ยม

ฉันต้องเขียนโค้ด reverse เพื่อให้สามารถเลือกจากกล่องและคืนค่า enum ในประเภทที่ถูกต้อง

ฉันยังแก้ไขรหัสเพื่อจัดการกรณีและปัญหาที่ขาดหายไป

เพื่อประโยชน์ของคนต่อไปนี่คือทางออกสุดท้ายของฉัน

public static class Program
{
   static void Main(string[] args)
    {
       // display the description attribute from the enum
       foreach (Colour type in (Colour[])Enum.GetValues(typeof(Colour)))
       {
            Console.WriteLine(EnumExtensions.ToName(type));
       }

       // Get the array from the description
       string xStr = "Yellow";
       Colour thisColour = EnumExtensions.FromName<Colour>(xStr);

       Console.ReadLine();
    }

   public enum Colour
   {
       [Description("Colour Red")]
       Red = 0,

       [Description("Colour Green")]
       Green = 1,

       [Description("Colour Blue")]
       Blue = 2,

       Yellow = 3
   }
}

public static class EnumExtensions
{

    // This extension method is broken out so you can use a similar pattern with 
    // other MetaData elements in the future. This is your base method for each.
    public static T GetAttribute<T>(this Enum value) where T : Attribute
    {
        var type = value.GetType();
        var memberInfo = type.GetMember(value.ToString());
        var attributes = memberInfo[0].GetCustomAttributes(typeof(T), false);

        // check if no attributes have been specified.
        if (((Array)attributes).Length > 0)
        {
            return (T)attributes[0];
        }
        else
        {
            return null;
        }
    }

    // This method creates a specific call to the above method, requesting the
    // Description MetaData attribute.
    public static string ToName(this Enum value)
    {
        var attribute = value.GetAttribute<DescriptionAttribute>();
        return attribute == null ? value.ToString() : attribute.Description;
    }

    /// <summary>
    /// Find the enum from the description attribute.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="desc"></param>
    /// <returns></returns>
    public static T FromName<T>(this string desc) where T : struct
    {
        string attr;
        Boolean found = false;
        T result = (T)Enum.GetValues(typeof(T)).GetValue(0);

        foreach (object enumVal in Enum.GetValues(typeof(T)))
        {
            attr = ((Enum)enumVal).ToName();

            if (attr == desc)
            {
                result = (T)enumVal;
                found = true;
                break;
            }
        }

        if (!found)
        {
            throw new Exception();
        }

        return result;
    }
}

}


1
ผู้ชายฉันได้เห็นวิธีแก้ปัญหาที่โง่และไม่ได้อธิบายมากมายและคุณฆ่ามัน ขอบคุณมาก <3
Kadaj

2

หากคุณenumมีค่าเช่นEqualsคุณอาจเจอข้อบกพร่องเล็กน้อยโดยใช้ส่วนขยายบางส่วนในคำตอบมากมายที่นี่ นี้เป็นเพราะมันจะสันนิษฐานว่าปกติtypeof(YourEnum).GetMember(YourEnum.Value)จะกลับมาเพียงค่าเดียวซึ่งเป็นของคุณMemberInfo enumต่อไปนี้เป็นรุ่นที่ปลอดภัยเล็กน้อยคำตอบอดัมครอว์ฟของ

public static class AttributeExtensions
{
    #region Methods

    public static T GetAttribute<T>(this Enum enumValue) where T : Attribute
    {
        var type = enumValue.GetType();
        var memberInfo = type.GetMember(enumValue.ToString());
        var member = memberInfo.FirstOrDefault(m => m.DeclaringType == type);
        var attribute = Attribute.GetCustomAttribute(member, typeof(T), false);
        return attribute is T ? (T)attribute : null;
    }

    #endregion
}

1

วิธีการขยายนี้จะได้รับการเป็นตัวแทนสตริงของค่า Enum โดยใช้ XmlEnumAttribute หากไม่มี XmlEnumAttribute อยู่จะกลับไปที่ enum.ToString ()

public static string ToStringUsingXmlEnumAttribute<T>(this T enumValue)
    where T: struct, IConvertible
{
    if (!typeof(T).IsEnum)
    {
        throw new ArgumentException("T must be an enumerated type");
    }

    string name;

    var type = typeof(T);

    var memInfo = type.GetMember(enumValue.ToString());

    if (memInfo.Length == 1)
    {
        var attributes = memInfo[0].GetCustomAttributes(typeof(System.Xml.Serialization.XmlEnumAttribute), false);

        if (attributes.Length == 1)
        {
            name = ((System.Xml.Serialization.XmlEnumAttribute)attributes[0]).Name;
        }
        else
        {
            name = enumValue.ToString();
        }
    }
    else
    {
        name = enumValue.ToString();
    }

    return name;
}

1

และถ้าคุณต้องการรายชื่อเต็มคุณสามารถทำอะไรได้บ้าง

typeof (PharmacyConfigurationKeys).GetFields()
        .Where(x => x.GetCustomAttributes(false).Any(y => typeof(DescriptionAttribute) == y.GetType()))
        .Select(x => ((DescriptionAttribute)x.GetCustomAttributes(false)[0]).Description);

0

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

    [AttributeUsage(AttributeTargets.Field,AllowMultiple = false)]
public class EnumDisplayName : Attribute
{
    public string Name { get; private set; }
    public EnumDisplayName(string name)
    {
        Name = name;
    }
}

ตอนนี้เพราะฉันต้องการมันในนิยาม HtmlHelper ของ HtmlHelper Extension:

public static class EnumHelper
{
    public static string EnumDisplayName(this HtmlHelper helper,EPriceType priceType)
    {
        //Get every fields from enum
        var fields = priceType.GetType().GetFields();
        //Foreach field skipping 1`st fieldw which keeps currently sellected value
        for (int i = 0; i < fields.Length;i++ )
        {
            //find field with same int value
            if ((int)fields[i].GetValue(priceType) == (int)priceType)
            {
                //get attributes of found field
                var attributes = fields[i].GetCustomAttributes(false);
                if (attributes.Length > 0)
                {
                    //return name of found attribute
                    var retAttr = (EnumDisplayName)attributes[0];
                    return retAttr.Name;
                }
            }
        }
        //throw Error if not found
        throw new Exception("Błąd podczas ustalania atrybutów dla typu ceny allegro");
    }
}

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


0
    public enum DataFilters
    {
        [Display(Name= "Equals")]
        Equals = 1,// Display Name and Enum Name are same 
        [Display(Name= "Does Not Equal")]
        DoesNotEqual = 2, // Display Name and Enum Name are different             
    }

ตอนนี้มันจะสร้างข้อผิดพลาดในกรณีนี้ 1 "เท่ากับ"

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

ดังนั้นถ้ามันเป็นชื่อกลับ enum เดียวกันมากกว่าชื่อที่แสดงเพราะ enumMember.GetCustomAttribute () ได้รับ null ถ้า displayname และชื่อ enum เหมือนกัน .....


0

หรือคุณสามารถทำสิ่งต่อไปนี้:

List<SelectListItem> selectListItems = new List<SelectListItem>();

    foreach (var item in typeof(PaymentTerm).GetEnumValues())
    {
        var type = item.GetType();
        var name = type.GetField(item.ToString()).GetCustomAttributesData().FirstOrDefault()?.NamedArguments.FirstOrDefault().TypedValue.Value.ToString();
        selectListItems.Add(new SelectListItem(name, type.Name));

    }

0

นี่คือวิธีที่ฉันแก้ไขได้โดยไม่ต้องใช้ตัวช่วยหรือส่วนขยายที่กำหนดเองด้วย. NET core 3.1

ชั้น

public enum YourEnum
{
    [Display(Name = "Suryoye means Arameans")]
    SURYOYE = 0,
    [Display(Name = "Oromoye means Syriacs")]
    OROMOYE = 1,
}

มีดโกน

@using Enumerations

foreach (var name in Html.GetEnumSelectList(typeof(YourEnum)))
{
    <h1>@name.Text</h1>
}

1
ลองตอบคำถามโดยใช้มากกว่าวิธีที่คุณแก้ไข 'เริ่ม' โดยเริ่มจากการรับรู้ปัญหาและอธิบายว่าคุณคิดว่าวิธีนี้แก้ปัญหาได้อย่างไร โปรดจำไว้ว่าคำตอบของคุณอาจถูกนำออกมาจากบริบทในอีกหลายปีต่อจากนี้และจากนั้นจะไร้ประโยชน์เกือบ การเพิ่มมากขึ้นการเพิ่มบริบทจะช่วยเพิ่มระดับคำตอบของคุณและความเป็นไปได้ทางประวัติศาสตร์ / เอกสารสำคัญ
OldFart

0

เรื่องประสิทธิภาพ

หากคุณต้องการประสิทธิภาพที่ดีขึ้นนี่คือวิธีที่จะไป:

public static class AdvancedEnumExtensions
{
    /// <summary>
    /// Gets the custom attribute <typeparamref name="T"/> for the enum constant, if such a constant is defined and has such an attribute; otherwise null.
    /// </summary>
    public static T GetCustomAttribute<T>(this Enum value) where T : Attribute
    {
        return GetField(value)?.GetCustomAttribute<T>(inherit: false);
    }

    /// <summary>
    /// Gets the FieldInfo for the enum constant, if such a constant is defined; otherwise null.
    /// </summary>
    public static FieldInfo GetField(this Enum value)
    {
        ulong u64 = ToUInt64(value);
        return value
            .GetType()
            .GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static)
            .Where(f => ToUInt64(f.GetRawConstantValue()) == u64)
            .FirstOrDefault();
    }

    /// <summary>
    /// Checks if an enum constant is defined for this enum value
    /// </summary>
    public static bool IsDefined(this Enum value)
    {
        return GetField(value) != null;
    }

    /// <summary>
    /// Converts the enum value to UInt64
    /// </summary>
    public static ulong ToUInt64(this Enum value) => ToUInt64((object)value);

    private static ulong ToUInt64(object value)
    {
        switch (Convert.GetTypeCode(value))
        {
            case TypeCode.SByte:
            case TypeCode.Int16:
            case TypeCode.Int32:
            case TypeCode.Int64:
                return unchecked((ulong)Convert.ToInt64(value, CultureInfo.InvariantCulture));

            case TypeCode.Byte:
            case TypeCode.UInt16:
            case TypeCode.UInt32:
            case TypeCode.UInt64:
            case TypeCode.Char:
            case TypeCode.Boolean:
                return Convert.ToUInt64(value, CultureInfo.InvariantCulture);

            default: throw new InvalidOperationException("UnknownEnumType");
        }
    }
}

ทำไมจึงมีประสิทธิภาพดีกว่า

เนื่องจากวิธีการในตัวทุกคนใช้รหัสที่คล้ายกันมากยกเว้นพวกเขาจะเรียกใช้รหัสอื่น ๆ ที่เราไม่สนใจที่เราไม่สนใจเกี่ยวกับ รหัส Enum ของ C # นั้นค่อนข้างน่ากลัวโดยทั่วไป

โค้ดข้างต้นได้รับ Linq-ified และคล่องตัวดังนั้นจึงมีเพียงบิตที่เราสนใจ

ทำไมรหัสในตัวจึงช้า

อันดับแรกเกี่ยวกับ Enum.ToString () -vs- Enum.GetName (.. )

ใช้หลังเสมอ (หรือดีกว่ายังไม่มีตามที่จะชัดเจนด้านล่าง)

ToString () ใช้สิ่งที่อยู่ภายใน แต่อีกครั้งยังทำสิ่งอื่น ๆ ที่เราไม่ต้องการเช่นพยายามรวมแฟล็กพิมพ์ตัวเลข ฯลฯ เราสนใจเฉพาะค่าคงที่ที่กำหนดไว้ใน enum

Enum.GetName รับค่าเขตข้อมูลทั้งหมดสร้างอาร์เรย์สตริงสำหรับชื่อทั้งหมดใช้ ToUInt64 ด้านบนของ RawConstantValues ​​ทั้งหมดเพื่อสร้างอาร์เรย์ UInt64 ของค่าทั้งหมดเรียงลำดับอาร์เรย์ทั้งสองตามค่า UInt64 และสุดท้ายได้รับชื่อจาก ชื่ออาร์เรย์ด้วยการทำ BinarySearch ในอาร์เรย์ UInt64 เพื่อค้นหาดัชนีของค่าที่เราต้องการ

... จากนั้นเราก็โยนฟิลด์และอาร์เรย์ที่เรียงแล้วออกไปใช้ชื่อนั้นเพื่อค้นหาฟิลด์อีกครั้ง

หนึ่งคำ: "ฮึ!"


-1

หรือคุณสามารถทำสิ่งต่อไปนี้:

Dictionary<FunkyAttributesEnum, string> description = new Dictionary<FunkyAttributesEnum, string>()
    {
      { FunkyAttributesEnum.NameWithoutSpaces1, "Name With Spaces1" },
      { FunkyAttributesEnum.NameWithoutSpaces2, "Name With Spaces2" },
    };

และรับคำอธิบายดังต่อไปนี้:

string s = description[FunkyAttributesEnum.NameWithoutSpaces1];

ในความคิดของฉันนี่เป็นวิธีที่มีประสิทธิภาพมากขึ้นในการทำสิ่งที่คุณต้องการให้สำเร็จเพราะไม่จำเป็นต้องมีการสะท้อนกลับ ..


2
แน่นอน แต่การไตร่ตรองนั้นไม่เลวร้ายอย่างที่ผู้คนทำ
Bryan Rowe

ไม่ได้บอกว่ามันแย่ - ฉันใช้มันตลอดเวลา มันมักจะใช้โดยไม่จำเป็นแม้ว่า :)
เอียน P

44
วิธีการแก้ปัญหานี้ย้ายคำอธิบายออกจาก enum ตัวเองสร้างอย่างน้อยสองปัญหาใหญ่ ก่อนอื่นถ้ามีคนเพิ่มค่าคงที่ enum ใหม่พวกเขาจะต้องรู้ว่าจะต้องไปที่อื่นเพื่อเพิ่มรายการที่นั่นด้วย แอตทริบิวต์เป็นสัญญาณที่ชัดเจนสำหรับผู้ดูแลในสิ่งที่พวกเขาต้องทำ ปัญหาที่สองของฉันคือมันเป็นรหัสมากขึ้น คุณสมบัติมีขนาดกะทัดรัด
scobi

1
@scott แต่มันช่วยให้คุณระบุคำสั่งซื้อของคุณเองและยกเว้นค่าที่คุณไม่ต้องการแสดงซึ่งเกือบจะเป็นสิ่งที่ฉันต้องการจริง ๆ
Simon_Weaver

-2

นอกจากนี้คุณยังสามารถกำหนดค่า enum เช่นName_Without_Spacesและเมื่อคุณต้องการคำอธิบายใช้Name_Without_Spaces.ToString().Replace('_', ' ')เพื่อแทนที่ขีดล่างด้วยช่องว่าง


8
นี่เป็นวิธีที่ไม่เหมาะสมอย่างมาก ลองใช้วิธีแก้ปัญหาที่ได้รับจาก @Bryan
Johann
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.