Mendapatkan atribut nilai Enum


483

Saya ingin tahu apakah mungkin untuk mendapatkan atribut dari enumnilai dan bukan dari nilai enumitu sendiri? Sebagai contoh, misalkan saya memiliki yang berikut ini enum:

using System.ComponentModel; // for DescriptionAttribute

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

Apa yang saya inginkan adalah tipe enum, menghasilkan 2-tuple nilai string enum dan deskripsinya.

Nilai itu mudah:

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

Tapi bagaimana cara mendapatkan nilai atribut deskripsi, untuk mengisi Tuple.Desc? Saya bisa memikirkan bagaimana melakukannya jika atribut milik enumitu sendiri, tetapi saya bingung bagaimana cara mendapatkannya dari nilai enum.




2
namespace yang diperlukan untuk Deskripsi adalah System.ComponentModel
John M

Anda juga bisa tidak menggunakan System.ComponentModel dan hanya menggunakan tipe atribut Anda sendiri; benar-benar tidak ada yang istimewa tentang itu DescriptionAttribute.
jrh

Jawaban:


482

Ini harus melakukan apa yang Anda butuhkan.

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
Opsional gunakan type.GetFields (BindingFlags.Public | BindingFlags.Static) untuk mendapatkan semua memInfos sekaligus.
TrueWill

4
Saya harus mengetik (FunkyAttributesEnum), tetapi selain itu berfungsi dengan baik. Terima kasih.
Greg Randall

@AlexK Saya tidak melihat kelas Enum memiliki properti NameWithoutSpaces1. Dari mana FunkyAttributesEnum.NameWithoutSpaces1 berasal?
Don

2
@ Don, ini adalah nama anggota enum dari pertanyaan OP.
MEMark

287

Sepotong kode ini akan memberi Anda metode ekstensi kecil yang bagus pada enum apa pun yang memungkinkan Anda mengambil atribut generik. Saya percaya ini berbeda dengan fungsi lambda di atas karena lebih mudah digunakan dan sedikit - Anda hanya perlu memasukkan tipe generik.

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
Penggunaan selanjutnya adalah: string desc = myEnumVariable.GetAttributeOfType <DescriptionAttribute> () .Description;
Brad Rem

2
Saya suka yang ini lebih dari Scott, karena penggunaannya lebih bersih di sini (kurang mengetik), jadi +1 :)
nawfal

3
Jika tidak ada atribut, bukankah ini akan melempar IndexOutOfRangeException?
Erik Philips

6
lebih baik gunakan type.GetMember (Enum.GetName (type, enumVal)) untuk memInfo sebagai enumVal.ToString () mungkin tidak dapat diandalkan untuk lokal yang berbeda.
Lin Song Yang

2
Apa gunanya menelepon GetCustomAttributes()lalu mendapatkan elemen pertama alih-alih menelepon GetCustomAttribute()?
tigrou

81

Ini adalah implementasi generik menggunakan lambda untuk seleksi

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

Sebut saja seperti ini:

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

4
Ini bagus. Kita hanya harus berhati-hati jika nilai enumerasi yang diberikan adalah kombinasi (diizinkan oleh FlagsAttribute). Dalam hal ini, enumeration.GetType().GetMember(enumeration.ToString())[0]akan gagal.
remio

Terpendek Anda bisa menulis:, value.GetType().GetField(value.ToString()).GetCustomAttributes(false).OfType<T>‌​().SingleOrDefault()tetapi harus mengakui cara eksplisit Anda lebih baik.
nawfal

2
Saya juga menambahkan String GetDescription publik statis (enum enum ini) {return enumeration.GetAttributeValue <DescriptionAttribute, String> (x => x.Description); } dengan cara itu hanya targetLevel.GetDescription ();
MarkKGreenway

65

Saya telah menggabungkan beberapa jawaban di sini untuk membuat solusi yang lebih fleksibel. Saya menyediakannya untuk berjaga-jaga jika itu bermanfaat bagi orang lain di masa depan. Posting asli di sini .

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

}

Solusi ini menciptakan sepasang metode ekstensi pada Enum. Yang pertama memungkinkan Anda menggunakan refleksi untuk mengambil atribut apa pun yang terkait dengan nilai Anda. Panggilan kedua secara khusus mengambil DescriptionAttributedan mengembalikan Descriptionnilainya.

Sebagai contoh, pertimbangkan untuk menggunakan DescriptionAttributeatribut dariSystem.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
}

Untuk menggunakan metode ekstensi di atas, sekarang Anda cukup memanggil yang berikut:

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

atau

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

Pada baris terakhir, maksud Anda "atribut. Deskripsi"? mengembalikan atribut == null? value.ToString (): attribute.Description;
Jeson Martajaya

2
Saya suka solusi ini, tetapi ada bug di dalamnya. Metode GetAttribute mengasumsikan bahwa nilai enum memiliki atribut Deskripsi dan melemparkan pengecualian ketika panjang atribut adalah 0. Ganti atribut "return (T) [0];" dengan "return (atribut.Panjang> 0? (T) atribut [0]: null);"
Simon Gymer

@SimonGymer terima kasih atas sarannya - Saya telah memperbarui yang sesuai. :)
Troy Alford

38

Selain tanggapan AdamCrawford , saya telah membuat metode penyuluhan yang lebih khusus yang memberikannya untuk mendapatkan deskripsi.

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

karenanya, untuk mendapatkan deskripsi, Anda bisa menggunakan metode ekstensi asli sebagai

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

atau Anda cukup memanggil metode ekstensi di sini sebagai:

string desc = myEnumVariable.GetAttributeDescription();

Yang diharapkan semoga membuat kode Anda sedikit lebih mudah dibaca.


16

Lancar satu liner ...

Di sini saya menggunakan DisplayAttributeyang berisi properti Namedan Description.

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

Contoh

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

Keluaran

Name: Sea cruise 
Description: Cruising on a dinghy

2
Saya menggunakan ini juga, itu yang paling bersih dari semua jawaban! +1
Mafii

Ini sepertinya cukup berguna! Thnx
Irf

7

Berikut ini kode untuk mendapatkan informasi dari atribut Display. Ini menggunakan metode generik untuk mengambil atribut. Jika atribut tidak ditemukan, itu mengubah nilai enum ke string dengan case pascal / unta dikonversi ke case title (kode diperoleh di sini )

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

Dan ini adalah metode ekstensi untuk string untuk mengkonversi ke judul kasus:

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

Saya menerapkan metode ekstensi ini untuk mendapatkan deskripsi dari nilai enum. Ini bekerja untuk semua jenis enum.

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

versi generik dari solusi yang sama sudah diposting. imo, lebih baik.
nawfal

4

Dapatkan kamus dari enum.

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

Sekarang panggil ini seperti ...

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

Metode EnumDecription Ext

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

Inilah versi .NET Core dari jawaban AdamCrawford, menggunakan 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];
    }
}

Saya tidak percaya. NET Core (atau lebih tepatnya, Standar sekarang) memiliki GetMember jadi saya tidak yakin bagaimana ini akan bekerja.
Jeff

Ada di System.Reflection.TypeExtensions, saya telah merevisi jawaban saya untuk daftar ini.
wonea

1
Gotcha, terima kasih. Saya pikir mungkin ada beberapa ekstensi yang sedang dimainkan.
Jeff

3

Menambahkan solusi saya untuk Net Framework dan NetCore.

Saya menggunakan ini untuk implementasi Net Framework saya:

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

Ini tidak berfungsi untuk NetCore jadi saya memodifikasinya untuk melakukan ini:

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

Contoh Pencacahan:

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

Contoh Penggunaan untuk statis ditambahkan:

var myDescription = myEnum.Description();

2

Dengan memanfaatkan beberapa fitur bahasa C # yang lebih baru, Anda dapat mengurangi jumlah baris:

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

Saya jawaban ini untuk menyiapkan kotak kombo dari atribut enum yang hebat.

Saya kemudian perlu kode kebalikan sehingga saya bisa mendapatkan pilihan dari kotak dan mengembalikan enum dalam jenis yang benar.

Saya juga memodifikasi kode untuk menangani kasus di mana atribut hilang

Untuk manfaat orang berikutnya, inilah solusi terakhir saya

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
Saya telah melihat begitu banyak solusi bodoh dan tidak dapat dijelaskan, dan solusi Anda membunuhnya. Terima kasih banyak <3
Kadaj

2

Jika Anda enummengandung nilai seperti EqualsAnda mungkin menabrak beberapa bug menggunakan beberapa ekstensi dalam banyak jawaban di sini. Ini karena biasanya diasumsikan bahwa typeof(YourEnum).GetMember(YourEnum.Value)hanya akan mengembalikan satu nilai, yang merupakan nilai MemberInfoAnda enum. Inilah jawaban versi Adam Crawford yang sedikit lebih aman .

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

Metode ekstensi ini akan mendapatkan representasi string dari nilai enum menggunakan XmlEnumAttribute-nya. Jika tidak ada XmlEnumAttribute, itu kembali ke 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

Dan jika Anda ingin daftar nama lengkap, Anda dapat melakukan sesuatu seperti

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

0

Guys jika membantu saya akan berbagi dengan Anda solusi saya: Definisi atribut Kustom:

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

Sekarang karena saya membutuhkannya di dalam definisi HtmlHelper tentang Ekstensi HtmlHelper:

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

Semoga ini bisa membantu


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             
    }

Sekarang akan menghasilkan kesalahan dalam kasus ini 1 "Setara"

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

jadi jika itu sama mengembalikan nama enum daripada nama tampilan karena enumMember.GetCustomAttribute () mendapat null jika tampilanname dan nama enum sama .....


0

Atau, Anda dapat melakukan hal berikut:

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

Ini adalah bagaimana saya menyelesaikannya tanpa menggunakan bantuan kustom atau ekstensi dengan .NET core 3.1.

Kelas

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

Pisau cukur

@using Enumerations

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

1
pertimbangkan untuk menjawab pertanyaan menggunakan lebih dari bagaimana Anda memecahkan 'itu' - mulailah dengan mengakui masalah dan menjelaskan bagaimana menurut Anda ini memecahkan 'itu'. Ingat jawaban Anda dapat diambil di luar konteks dalam beberapa tahun dari sekarang dan kemudian akan hampir tidak berguna. Menambahkan lebih banyak ke dalamnya, menambahkan beberapa konteks akan meningkatkan jawaban Anda dan kemungkinan relevansi historis / arsip
OldFart

0

Masalah kinerja

Jika Anda ingin kinerja yang lebih baik, inilah cara yang harus dilakukan:

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

Mengapa ini memiliki kinerja yang lebih baik?

Karena metode bawaan semua menggunakan kode yang sangat mirip dengan ini kecuali mereka juga menjalankan banyak kode lain yang tidak kami pedulikan . Kode Enum C # cukup mengerikan pada umumnya.

Kode di atas telah Linq-ified dan efisien sehingga hanya berisi bit yang kita pedulikan.

Mengapa kode bawaan lambat?

Pertama tentang Enum.ToString () -vs- Enum.GetName (..)

Selalu gunakan yang terakhir. (Atau lebih baik lagi, seperti yang akan menjadi jelas di bawah ini.)

ToString () menggunakan yang terakhir secara internal, tetapi sekali lagi, juga melakukan banyak hal lain yang tidak kita inginkan, misalnya mencoba untuk menggabungkan bendera, mencetak angka dll. Kami hanya tertarik pada konstanta yang didefinisikan di dalam enum.

Enum.GetName mendapatkan semua bidang, membuat array string untuk semua nama, menggunakan ToUInt64 di atas pada semua RawConstantValues ​​mereka untuk membuat array UInt64 dari semua nilai, mengurutkan kedua array berdasarkan nilai UInt64, dan akhirnya mendapatkan nama dari array nama dengan melakukan BinarySearch di array UInt64 untuk menemukan indeks nilai yang kita inginkan.

... dan kemudian kita membuang bidang dan array yang disortir pergi menggunakan nama itu untuk menemukan bidang lagi.

Satu kata: "Ugh!"


-1

Atau, Anda dapat melakukan hal berikut:

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

Dan dapatkan deskripsi dengan yang berikut ini:

string s = description[FunkyAttributesEnum.NameWithoutSpaces1];

Menurut pendapat saya ini adalah cara yang lebih efisien untuk melakukan apa yang ingin Anda capai, karena tidak diperlukan refleksi ..


2
Tentu, tetapi refleksi tidak seburuk orang-orang.
Bryan Rowe

Tidak mengatakan itu buruk - saya menggunakannya sepanjang waktu. Namun, sering digunakan tanpa perlu. :)
Ian P

44
Solusi ini memindahkan deskripsi dari enum itu sendiri, menciptakan setidaknya dua masalah besar. Pertama, jika seseorang menambahkan konstanta enum baru, mereka perlu tahu untuk pergi ke tempat lain ini untuk menambahkan entri di sana juga. Atribut adalah tanda yang jelas bagi pengelola apa yang harus mereka lakukan. Masalah kedua saya adalah bahwa itu hanya kode yang lebih banyak. Atributnya kompak.
scobi

1
@scott tetapi memungkinkan Anda menentukan pesanan Anda sendiri, dan mengecualikan nilai yang tidak ingin Anda tampilkan yang hampir selalu seperti yang sebenarnya saya inginkan
Simon_Weaver

-2

Anda juga dapat menentukan nilai enum seperti Name_Without_Spaces, dan saat Anda menginginkan deskripsi digunakan Name_Without_Spaces.ToString().Replace('_', ' ')untuk mengganti garis bawah dengan spasi.


8
Ini adalah solusi yang sangat tidak tepat. Pertimbangkan untuk menggunakan solusi yang disediakan oleh @Bryan
Johann
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.