Pertanyaan Representasi string dari Enum


Saya memiliki pencacahan berikut:

public enum AuthenticationMethod
{
    FORMS = 1,
    WINDOWSAUTHENTICATION = 2,
    SINGLESIGNON = 3
}

Namun masalahnya adalah bahwa saya membutuhkan kata "FORMS" ketika saya meminta AuthenticationMethod.FORMS dan bukan id 1.

Saya telah menemukan solusi berikut untuk masalah ini (link):

Pertama saya harus membuat atribut khusus yang disebut "StringValue":

public class StringValue : System.Attribute
{
    private readonly string _value;

    public StringValue(string value)
    {
        _value = value;
    }

    public string Value
    {
        get { return _value; }
    }

}

Kemudian saya dapat menambahkan atribut ini ke enumerator saya:

public enum AuthenticationMethod
{
    [StringValue("FORMS")]
    FORMS = 1,
    [StringValue("WINDOWS")]
    WINDOWSAUTHENTICATION = 2,
    [StringValue("SSO")]
    SINGLESIGNON = 3
}

Dan tentu saja saya butuh sesuatu untuk mengambil StringValue itu:

public static class StringEnum
{
    public static string GetStringValue(Enum value)
    {
        string output = null;
        Type type = value.GetType();

        //Check first in our cached results...

        //Look for our 'StringValueAttribute' 

        //in the field's custom attributes

        FieldInfo fi = type.GetField(value.ToString());
        StringValue[] attrs =
           fi.GetCustomAttributes(typeof(StringValue),
                                   false) as StringValue[];
        if (attrs.Length > 0)
        {
            output = attrs[0].Value;
        }

        return output;
    }
}

Bagus sekarang saya punya alat untuk mendapatkan nilai string untuk enumerator. Saya kemudian dapat menggunakannya seperti ini:

string valueOfAuthenticationMethod = StringEnum.GetStringValue(AuthenticationMethod.FORMS);

Oke sekarang semua ini bekerja seperti pesona tetapi saya menemukan itu banyak pekerjaan. Saya ingin tahu apakah ada solusi yang lebih baik untuk ini.

Saya juga mencoba sesuatu dengan kamus dan properti statis tetapi itu tidak lebih baik.


823
2018-01-08 14:15


asal


Jawaban:


Mencoba tipe-aman-enum pola.

public sealed class AuthenticationMethod {

    private readonly String name;
    private readonly int value;

    public static readonly AuthenticationMethod FORMS = new AuthenticationMethod (1, "FORMS");
    public static readonly AuthenticationMethod WINDOWSAUTHENTICATION = new AuthenticationMethod (2, "WINDOWS");
    public static readonly AuthenticationMethod SINGLESIGNON = new AuthenticationMethod (3, "SSN");        

    private AuthenticationMethod(int value, String name){
        this.name = name;
        this.value = value;
    }

    public override String ToString(){
        return name;
    }

}

Memperbarui Konversi jenis eksplisit (atau implisit) dapat dilakukan oleh

  • menambahkan medan statis dengan pemetaan

    private static readonly Dictionary<string, AuthenticationMethod> instance = new Dictionary<string,AuthenticationMethod>();
    
    • n.b. Agar inisialisasi bidang "enum member" tidak membuang NullReferenceException saat memanggil konstruktor instance, pastikan untuk meletakkan bidang Kamus sebelum bidang "enum member" di kelas Anda. Ini karena penginisialisasi field statis dipanggil dalam urutan deklarasi, dan sebelum konstruktor statis, menciptakan situasi yang aneh dan perlu tetapi membingungkan sehingga konstruktor instance dapat dipanggil sebelum semua field statis telah diinisialisasi, dan sebelum konstruktor statis dipanggil.
  • mengisi pemetaan ini dalam konstruktor contoh

    instance[name] = this;
    
  • dan menambahkan operator konversi tipe yang ditentukan pengguna

    public static explicit operator AuthenticationMethod(string str)
    {
        AuthenticationMethod result;
        if (instance.TryGetValue(str, out result))
            return result;
        else
            throw new InvalidCastException();
    }
    

814
2018-01-08 14:29



Gunakan metode

Enum.GetName(Type MyEnumType,  object enumvariable)  

seperti dalam (Asumsikan Shipper adalah Enum yang ditentukan)

Shipper x = Shipper.FederalExpress;
string s = Enum.GetName(typeof(Shipper), x);

Ada banyak metode statis lainnya di kelas Enum yang layak diselidiki juga ...


209
2018-01-08 14:19



Anda dapat mereferensikan nama daripada nilai dengan menggunakan ToString ()

Console.WriteLine("Auth method: {0}", AuthenticationMethod.Forms.ToString());

Dokumentasi ada di sini:

http://msdn.microsoft.com/en-us/library/16c1xs4z.aspx

... dan jika Anda menamai enums Anda dalam Pascal Case (seperti yang saya lakukan - seperti ThisIsMyEnumValue = 1 dll) maka Anda bisa menggunakan regex yang sangat sederhana untuk mencetak formulir ramah:

static string ToFriendlyCase(this string EnumString)
{
    return Regex.Replace(EnumString, "(?!^)([A-Z])", " $1");
}

yang dapat dengan mudah dipanggil dari string apa pun:

Console.WriteLine("ConvertMyCrazyPascalCaseSentenceToFriendlyCase".ToFriendlyCase());

Hasil:

Mengubah Kalimat Kasus Gila Pascal Saya Menjadi Kasus yang Ramah

Yang menghemat menjalankan semua jalan di sekitar rumah menciptakan atribut kustom dan melampirkannya ke enum Anda atau menggunakan tabel pencarian untuk menikah nilai enum dengan string ramah dan terbaik dari semua itu mengelola diri dan dapat digunakan pada setiap string Pascal Case yang tak terhingga lebih dapat digunakan kembali. Tentu saja, itu tidak memungkinkan Anda untuk memiliki berbeda nama ramah dari enum Anda yang menyediakan solusi Anda.

Saya suka solusi asli Anda meskipun untuk skenario yang lebih kompleks sekalipun. Anda dapat mengambil solusi satu langkah lebih jauh dan menjadikan GetStringValue sebagai metode ekstensi enum Anda dan kemudian Anda tidak perlu mereferensikannya seperti StringEnum.GetStringValue ...

public static string GetStringValue(this AuthenticationMethod value)
{
  string output = null;
  Type type = value.GetType();
  FieldInfo fi = type.GetField(value.ToString());
  StringValue[] attrs = fi.GetCustomAttributes(typeof(StringValue), false) as StringValue[];
  if (attrs.Length > 0)
    output = attrs[0].Value;
  return output;
}

Anda kemudian dapat mengaksesnya dengan mudah langsung dari instance enum Anda:

Console.WriteLine(AuthenticationMethod.SSO.GetStringValue());

74
2018-01-08 14:20



Sayangnya refleksi untuk mendapatkan atribut pada enum cukup lambat:

Lihat pertanyaan ini: Adakah yang tahu cara cepat untuk mendapatkan atribut khusus pada nilai enum?

Itu .ToString() cukup lambat di enums juga.

Anda dapat menulis metode ekstensi untuk enum meskipun:

public static string GetName( this MyEnum input ) {
    switch ( input ) {
        case MyEnum.WINDOWSAUTHENTICATION:
            return "Windows";
        //and so on
    }
}

Ini tidak bagus, tetapi akan cepat dan tidak memerlukan refleksi untuk atribut atau nama field.


C # 6 Pembaruan

Jika Anda bisa menggunakan C # 6 maka baru nameof operator berfungsi untuk enum, jadi nameof(MyEnum.WINDOWSAUTHENTICATION) akan dikonversi menjadi "WINDOWSAUTHENTICATION" di waktu kompilasi, menjadikannya cara tercepat untuk mendapatkan nama enum.

Perhatikan bahwa ini akan mengonversi enum eksplisit menjadi konstanta inline, sehingga tidak berfungsi untuk enum yang Anda miliki dalam sebuah variabel. Begitu:

nameof(AuthenticationMethod.FORMS) == "FORMS"

Tapi...

var myMethod = AuthenticationMethod.FORMS;
nameof(myMethod) == "myMethod"

63
2018-02-11 00:15



Saya menggunakan metode ekstensi:

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

Sekarang hiasi enum dengan:

public enum AuthenticationMethod
{
    [Description("FORMS")]
    FORMS = 1,
    [Description("WINDOWSAUTHENTICATION")]
    WINDOWSAUTHENTICATION = 2,
    [Description("SINGLESIGNON ")]
    SINGLESIGNON = 3
}

Ketika Anda menelepon

AuthenticationMethod.FORMS.ToDescription() kamu akan mendapatkan "FORMS".


52
2017-09-06 15:50



Cukup gunakan ToString() metode

public enum any{Tomato=0,Melon,Watermelon}

Untuk referensi string Tomato, gunakan saja

any.Tomato.ToString();

36
2018-01-08 14:30



Saya menggunakan atribut Deskripsi dari namespace System.ComponentModel. Cukup hias enum dan kemudian gunakan kode ini untuk mengambilnya:

public static string GetDescription<T>(this object enumerationValue)
            where T : struct
        {
            Type type = enumerationValue.GetType();
            if (!type.IsEnum)
            {
                throw new ArgumentException("EnumerationValue must be of Enum type", "enumerationValue");
            }

            //Tries to find a DescriptionAttribute for a potential friendly name
            //for the enum
            MemberInfo[] memberInfo = type.GetMember(enumerationValue.ToString());
            if (memberInfo != null && memberInfo.Length > 0)
            {
                object[] attrs = memberInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);

                if (attrs != null && attrs.Length > 0)
                {
                    //Pull out the description value
                    return ((DescriptionAttribute)attrs[0]).Description;
                }
            }
            //If we have no description attribute, just return the ToString of the enum
            return enumerationValue.ToString();

        }

Sebagai contoh:

public enum Cycle : int
{        
   [Description("Daily Cycle")]
   Daily = 1,
   Weekly,
   Monthly
}

Kode ini dengan baik melayani untuk enums di mana Anda tidak memerlukan "Nama ramah" dan akan kembali hanya .ToString () dari enum.


26
2017-09-22 20:46