Enum ToString dengan string ramah pengguna

282

Enum saya terdiri dari nilai-nilai berikut:

private enum PublishStatusses{
    NotCompleted,
    Completed,
    Error
};

Saya ingin dapat menampilkan nilai-nilai ini dengan cara yang ramah pengguna.
Saya tidak perlu bisa beralih dari string ke nilai lagi.

Boris Callens
sumber
kemungkinan duplikat dari C # String enums
nawfal
Kemungkinan duplikasi representasi String dari Enum
Liam

Jawaban:

350

Saya menggunakan Descriptionatribut dari namespace System.ComponentModel. Cukup dekorasikan enum:

private enum PublishStatusValue
{
    [Description("Not Completed")]
    NotCompleted,
    Completed,
    Error
};

Kemudian gunakan kode ini untuk mengambilnya:

public static string GetDescription<T>(this T 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();
}
Ray Booysen
sumber
12
Contoh ini lebih mudah dibaca. stackoverflow.com/questions/1415140/…
RayLoveless
31
Saya menduga ada hit kinerja yang signifikan untuk menggunakan refleksi seperti yang dijelaskan dalam solusi ini. Kode untuk metode Will menggunakan metode ekstensi ToFriendlyString jauh lebih mudah dipahami, dan kinerjanya juga harus sangat cepat.
humbads
1
Saya suka versi yang terhubung dengan @RayL karena hanya akan menambahkan metode ekstensi ke Enums. Jika hanya itu yang ingin Anda gunakan untuk ini (seperti yang ditunjukkan dengan ArgumentException, maka tidak ada alasan untuk membuat metode ini sepenuhnya generik.
krillgar
4
Itu berarti bahwa setiap enum membutuhkan metode ekstensi sendiri. Ini adalah penggunaan yang lebih umum dan memang membutuhkan lebih banyak pekerjaan, tetapi Anda mungkin ingin mengukur apa arti "cepat" sebelum kita memutuskan kinerja.
Ray Booysen
2
@petar yang berfungsi tetapi tidak jika Anda ingin string ramah ditampilkan ke pengguna. MY_TYPE akan memiliki garis bawah dan tidak dapat disesuaikan.
Ray Booysen
354

Saya melakukan ini dengan metode ekstensi:

public enum ErrorLevel
{
  None,
  Low,
  High,
  SoylentGreen
}

public static class ErrorLevelExtensions
{
  public static string ToFriendlyString(this ErrorLevel me)
  {
    switch(me)
    {
      case ErrorLevel.None:
        return "Everything is OK";
      case ErrorLevel.Low:
        return "SNAFU, if you know what I mean.";
      case ErrorLevel.High:
        return "Reaching TARFU levels";
      case ErrorLevel.SoylentGreen:
        return "ITS PEOPLE!!!!";
      default:
        return "Get your damn dirty hands off me you FILTHY APE!";
    }
  }
}

sumber
6
Ini jauh lebih bersih daripada jawaban Atribut. Bagus!
Pennyrave
3
@pennyrave: Eh. Banyak komponen UI mengharapkan untuk menemukan dan menggunakan DisplayNameAttribute dan DescriptionAttribute. Bahkan, sekarang, saya menggunakan ini dan metode ekstensi untuk dengan mudah mengeluarkan nilai-nilai itu.
60
Masalah yang saya lihat dengan ini adalah Anda terus-menerus menulis metode ekstensi ini. Dengan mekanisme atribut, ini adalah cara sederhana untuk mendekorasi dan hanya memanggil satu metode.
Ray Booysen
5
Tidak yakin apa yang kamu maksud?
Ray Booysen
9
Lebih baik, menurut saya, untuk memungkinkan defaultimplementasi kasus kembali me.ToString()dan hanya memberikan pernyataan beralih kasus untuk nilai enum yang ingin Anda timpa. Dalam contoh Anda, saya mendapatkan bahwa semuanya berbeda tetapi dalam kasus penggunaan aktual, saya menduga bahwa sebagian besar nilai enum kata tunggal sudah cukup dan Anda hanya akan memberikan penggantian untuk nilai enum multi-kata.
Scott
78

Mungkin saya melewatkan sesuatu, tetapi apa yang salah dengan Enum. Dapatkan Nama?

public string GetName(PublishStatusses value)
{
    return Enum.GetName(typeof(PublishStatusses), value)
}

sunting: untuk string yang mudah digunakan, Anda harus melalui .resource untuk menyelesaikan internasionalisasi / lokalisasi, dan akan lebih baik menggunakan kunci tetap berdasarkan pada kunci enum daripada atribut dekorator pada saat yang sama.

annakata
sumber
12
Saya mengembalikan nilai literal enum, bukan yang ramah pengguna.
Boris Callens
2
oic - well ada kasus yang cukup besar bahwa Anda harus pergi melalui perpustakaan sumber daya string berdasarkan pada nilai ini, karena alternatif (attribs dekorator) tidak akan mendukung I18N
annakata
1
Dalam kasus I18N saya akan membuat metode GetDescription () mencari di lib sumber daya untuk string yang diterjemahkan dan kembali ke deskripsi dan kemudian kembali ke literal.
Boris Callens
3
+1 untuk MyEnum.ToString () sebagai kunci sumber daya untuk pelokalan. Saya telah melakukan itu selama bertahun
jackvsworld
1
@annakata kita sebenarnya telah memperluas mekanisme atribut untuk memasukkan dukungan untuk l18N, itu sebenarnya perubahan sederhana.
Ray Booysen
23

Saya membuat metode ekstensi terbalik untuk mengubah deskripsi kembali menjadi nilai enum:

public static T ToEnumValue<T>(this string enumerationDescription) where T : struct
{
    var type = typeof(T);

    if (!type.IsEnum)
        throw new ArgumentException("ToEnumValue<T>(): Must be of enum type", "T");

    foreach (object val in System.Enum.GetValues(type))
        if (val.GetDescription<T>() == enumerationDescription)
            return (T)val;

    throw new ArgumentException("ToEnumValue<T>(): Invalid description for enum " + type.Name, "enumerationDescription");
}
Brian Richardson
sumber
15
Maaf, tapi terima kasih telah mencoba membantu! Meskipun karena ini adalah situs tanya jawab, jawaban harus merupakan upaya untuk langsung menjawab pertanyaan. Dan pertanyaannya secara spesifik menyatakan, " Saya tidak perlu bisa beralih dari nilai ke nilai lagi. " Sekali lagi, terima kasih!
Jesse
8
Terima kasih atas kritik positifnya. Selalu sulit menjadi orang baru di sebuah situs dan belajar tentang budaya dan nuansa. Saya senang ada orang seperti Anda yang meluruskan orang baru. Sekali lagi, terima kasih tidak membuang cowok baru.
Brian Richardson
6
@Jesse Dan 4 tahun kemudian seseorang senang menemukan kode bjrichardson di sini! SO mungkin situs Q&A, tetapi itu tidak berarti pertanyaannya sudah mati setelah dijawab.
John
18

Solusi termudah di sini adalah dengan menggunakan metode ekstensi kustom (setidaknya. NET 3.5 - Anda bisa mengubahnya menjadi metode pembantu statis untuk versi kerangka kerja sebelumnya).

public static string ToCustomString(this PublishStatusses value)
{
    switch(value)
    {
        // Return string depending on value.
    }
    return null;
}

Saya berasumsi di sini bahwa Anda ingin mengembalikan sesuatu selain nama sebenarnya dari nilai enum (yang dapat Anda peroleh hanya dengan menelepon ToString).

Noldorin
sumber
Meskipun valid, saya lebih menyukai atributnya. Dengan cara itu saya bisa meletakkan metode toSTring saya di perpustakaan terpisah, sambil menempatkan representasi string khusus dengan enum itu sendiri
Boris Callens
1
Cukup adil. Saya kira salah satu keuntungan dari metode ini adalah bahwa Anda dapat menyertakan argumen dengan metode yang menentukan beberapa variabel status, dan kemudian mengubah representasi string apa yang dikembalikan tergantung pada ini.
Noldorin
1
Ya, itu semua tergantung pada ruang lingkup metode yang saya kira. Sementara cara Atribut lebih umum, solusi Anda lebih bersifat lokal .. Ini semua tentang kebutuhan pada akhirnya.
Boris Callens
1
Anda dapat menempatkan metode ekstensi di mana saja Anda inginkan. Anda hanya perlu referensi di mana Anda ingin menggunakannya.
Ya, tetapi ini berarti bahwa metode perluasan yang satu ini harus ditulis ulang setiap kali Anda memperkenalkan enum baru yang Anda ingin memiliki nama yang ramah. Ini juga berarti bahwa SEMUA aplikasi Anda akan membawa sekitar nama yang ramah untuk SEMUA aplikasi Anda yang lain ...
Boris Callens
13

Pos lain itu adalah Jawa. Anda tidak dapat memasukkan metode dalam Enums di C #.

lakukan saja seperti ini:

PublishStatusses status = ...
String s = status.ToString();

Jika Anda ingin menggunakan nilai tampilan yang berbeda untuk nilai enum Anda, Anda bisa menggunakan Atribut dan Refleksi.

Lemmy
sumber
3
toString tidak aman dalam semua kasus - enum dengan banyak entri dengan nilai yang sama (misalnya untuk integer enums) akan mengembalikan kunci dari nilai pencocokan pertama, bukan kunci dari item yang diuji, inilah mengapa Enum.GetName lebih disukai
annakata
4
Yah itu adalah solusi termudah untuk enum spesifiknya
Lemmy
9

Cara paling sederhana adalah dengan memasukkan kelas ekstensi ini ke dalam proyek Anda, itu akan bekerja dengan enum dalam proyek:

public static class EnumExtensions
{
    public static string ToFriendlyString(this Enum code)
    {
        return Enum.GetName(code.GetType(), code);
    }
}

Pemakaian:

enum ExampleEnum
{
    Demo = 0,
    Test = 1, 
    Live = 2
}

...

ExampleEnum ee = ExampleEnum.Live;
Console.WriteLine(ee.ToFriendlyString());
Milan Švec
sumber
2
Ini adalah misteri mengapa komentar ini bukan yang diterima, atau paling banyak dipilih - tidak ada refleksi, tidak ada atribut yang tidak perlu, ideal untuk situasi sederhana di mana enum sudah bernama baik. Anda dapat mengambil jawaban ini selangkah lebih maju dan memungkinkan untuk menambahkan spasi di antara huruf kapital sebelum kembali, 'My Enum'.
Vix
12
Jika enum sudah dinamai dengan baik, tidak perlu metode ekstensi apa pun. Cukup gunakan metode ToString () yang ada. string result = "Result: " + ee;
John
Ini harus menjadi jawaban terbaik. Ini bekerja untuk enum apa pun. Anda bahkan bisa mengimplementasikannya menggunakan Enum spesifik hanya dengan mengubah jenis parameter Enum ke Enual Aktual yang digunakan untuk menggunakannya.
Juanu Haedo
6
Jawaban ini dan semua komentar mengabaikan permintaan asli untuk deskripsi yang diperluas. Kalian benar-benar melewatkan latihan yang mengembalikan sesuatu selain dari nilai ToString default. Saya tidak akan mencatat semua catatan untuk jawaban ini di sini, tetapi saya yakin mau.
TonyG
8

Beberapa opsi lain yang lebih primitif yang menghindari kelas / tipe referensi:

  • Metode array
  • Metode struct bersarang

Metode array

private struct PublishStatusses
{
    public static string[] Desc = {
        "Not Completed",
        "Completed",
        "Error"
    };

    public enum Id
    {
        NotCompleted = 0,
        Completed,
        Error
    };
}

Pemakaian

string desc = PublishStatusses.Desc[(int)PublishStatusses.Id.Completed];

Metode struct bersarang

private struct PublishStatusses
{
    public struct NotCompleted
    {
        public const int Id = 0;
        public const string Desc = "Not Completed";
    }

    public struct Completed
    {
        public const int Id = 1;
        public const string Desc = "Completed";
    }

    public struct Error
    {
        public const int Id = 2;
        public const string Desc = "Error";
    }            
}

Pemakaian

int id = PublishStatusses.NotCompleted.Id;
string desc = PublishStatusses.NotCompleted.Desc;

Pembaruan (03/09/2018)

Hibrida Metode Penyuluhan dan teknik pertama di atas.

Saya lebih suka enum didefinisikan di mana mereka "milik" (paling dekat dengan sumber asalnya dan tidak dalam beberapa, namespace global umum).

namespace ViewModels
{
    public class RecordVM
    {
        //public enum Enum { Minutes, Hours }
        public struct Enum
        {
            public enum Id { Minutes, Hours }
            public static string[] Name = { "Minute(s)", "Hour(s)" };
        }
    }
}

Metode ekstensi tampaknya cocok untuk area umum, dan definisi "terlokalisasi" dari enum sekarang membuat metode ekstensi lebih verbose.

namespace Common
{
    public static class EnumExtensions
    {
        public static string Name(this RecordVM.Enum.Id id)
        {
            return RecordVM.Enum.Name[(int)id];
        }
    }   
}

Contoh penggunaan enum dan metode ekstensi itu.

namespace Views
{
    public class RecordView 
    {
        private RecordDataFieldList<string, string> _fieldUnit;

        public RecordView()
        {
            _fieldUnit.List = new IdValueList<string, string>
            {            
                new ListItem<string>((int)RecordVM.Enum.Id.Minutes, RecordVM.Enum.Id.Minutes.Name()),
                new ListItem<string>((int)RecordVM.Enum.Id.Hours, RecordVM.Enum.Id.Hours.Name())
            };
        }

        private void Update()
        {    
            RecordVM.Enum.Id eId = DetermineUnit();

            _fieldUnit.Input.Text = _fieldUnit.List.SetSelected((int)eId).Value;
        }
    }
}

Catatan: Saya benar-benar memutuskan untuk menghilangkan Enumpembungkus (dan Namearray), karena yang terbaik adalah string nama berasal dari sumber daya (yaitu file config atau DB) daripada kode keras, dan karena saya akhirnya meletakkan metode ekstensi di ViewModelsnamespace (hanya dalam file "CommonVM.cs" yang berbeda). Plus .Idsemuanya menjadi mengganggu dan rumit.

namespace ViewModels
{
    public class RecordVM
    {
        public enum Enum { Minutes, Hours }
        //public struct Enum
        //{
        //    public enum Id { Minutes, Hours }
        //    public static string[] Name = { "Minute(s)", "Hour(s)" };
        //}
    }
}

CommonVM.cs

//namespace Common
namespace ViewModels
{
    public static class EnumExtensions
    {
        public static string Name(this RecordVM.Enum id)
        {
            //return RecordVM.Enum.Name[(int)id];
            switch (id)
            {
                case RecordVM.Enum.Minutes: return "Minute(s)";                    
                case RecordVM.Enum.Hours: return "Hour(s)";
                default: return null;
            }
        }
    }   
}

Contoh penggunaan enum dan metode ekstensi itu.

namespace Views
{
    public class RecordView 
    {
        private RecordDataFieldList<string, string> _fieldUnit

        public RecordView()
        {
            _fieldUnit.List = new IdValueList<string, string>
            {            
                new ListItem<string>((int)RecordVM.Enum.Id.Minutes, RecordVM.Enum.Id.Minutes.Name()),
                new ListItem<string>((int)RecordVM.Enum.Id.Hours, RecordVM.Enum.Id.Hours.Name())
            };
        }

        private void Update()
        {    
            RecordVM.Enum eId = DetermineUnit();

            _fieldUnit.Input.Text = _fieldUnit.List.SetSelected((int)eId).Value;
        }
    }
}
Sam adalah
sumber
+ 1-1 = 0 suara: Solusi ini mempertahankan sintaks Enum dan menyelesaikan masalah tanpa refleksi atau kode yang rumit, jadi beri +1 di sana. Tapi itu kehilangan fitur Enums sendiri. Jadi sementara IMO ini adalah pilihan yang baik, itu tidak menjawab pertanyaan aktual dan mendapat -1. Net 0. Maaf kami tidak memiliki cara untuk merekam yang lebih baik di SO.
TonyG
@ TonyG Cukup adil. Setelah melewatkan beberapa pertanyaan pada penilaian keterampilan .net. Saya mulai menyadari betapa mendalamnya C # enum, jadi mungkin ide yang baik untuk setidaknya mengetahui kemampuan mereka sebelum memutuskan metodologi mana yang akan diterapkan (terutama untuk penggunaan meresap, refactoring) dapat sedikit waktu;).
samis
7

Anda dapat menggunakan Humanizer paket dengan Humanize Enums possiblity. Contoh:

enum PublishStatusses
{
    [Description("Custom description")]
    NotCompleted,
    AlmostCompleted,
    Error
};

maka Anda dapat menggunakan Humanizemetode ekstensi pada enum secara langsung:

var st1 = PublishStatusses.NotCompleted;
var str1 = st1.Humanize(); // will result in Custom description

var st2 = PublishStatusses.AlmostCompleted;
var str2 = st2.Humanize(); // will result in Almost completed (calculated automaticaly)
Konrad Kokosa
sumber
Ia menggunakan refleksi juga dan tidak di-cache. github.com/Humanizr/Humanizer/blob/…
Konrad
Ini akan selambat solusi dalam jawaban pertama oleh Ray
Konrad
5

Sehubungan dengan Ray Booysen, ada bug dalam kode: Enum ToString dengan string yang ramah pengguna

Anda perlu memperhitungkan beberapa atribut pada nilai enum.

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 && attrs.Where(t => t.GetType() == typeof(DescriptionAttribute)).FirstOrDefault() != null)
            {
                //Pull out the description value
                return ((DescriptionAttribute)attrs.Where(t=>t.GetType() == typeof(DescriptionAttribute)).FirstOrDefault()).Description;
            }
        }
        //If we have no description attribute, just return the ToString of the enum
        return enumerationValue.ToString();
Joel MC
sumber
4
Penghilangan cek untuk beberapa atribut Deskripsi sengaja dilakukan. Jika enum memiliki dua, dan Anda gunakan untuk menghasilkan deskripsi, saya ingin berpikir bahwa itu adalah keadaan yang luar biasa. Saya pikir bug yang sebenarnya adalah saya tidak melakukan Single () untuk memiliki pengecualian. Kalau tidak, seluruh tanda tangan metode tidak masuk akal. GetDescription ()? Deskripsi yang mana? Agregat?
Ray Booysen
4
public enum MyEnum
{
    [Description("Option One")]
    Option_One
}

public static string ToDescriptionString(this Enum This)
{
    Type type = This.GetType();

    string name = Enum.GetName(type, This);

    MemberInfo member = type.GetMembers()
        .Where(w => w.Name == name)
        .FirstOrDefault();

    DescriptionAttribute attribute = member != null
        ? member.GetCustomAttributes(true)
            .Where(w => w.GetType() == typeof(DescriptionAttribute))
            .FirstOrDefault() as DescriptionAttribute
        : null;

    return attribute != null ? attribute.Description : name;
}
Diogo Freitas
sumber
3
Itu selalu baik untuk menulis beberapa teks yang menjelaskan mengapa ini harus bekerja dan mengapa OP tidak.
phaberest
Hanya FYI, konvensi kode C # ingin variabel lokal dan parameter metode dengan huruf awal huruf kecil. Satu pengecualian adalah thisparameter dalam metode ekstensi, yang dapat Anda lihat dipanggil Thisdalam banyak contoh di web. Menyebutnya seperti tipenya seperti yang Anda lakukan ( Enum Enum) membuat kode kurang dibaca.
Massimiliano Kraus
4

Alih-alih menggunakan enum, gunakan kelas statis.

menggantikan

private enum PublishStatuses{
    NotCompleted,
    Completed,
    Error
};

dengan

private static class PublishStatuses{
    public static readonly string NotCompleted = "Not Completed";
    public static readonly string Completed = "Completed";
    public static readonly string Error = "Error";
};

itu akan digunakan seperti ini

PublishStatuses.NotCompleted; // "Not Completed"

Masalah menggunakan solusi "metode ekstensi" teratas:

Enum pribadi sering digunakan di dalam kelas lain. Solusi metode ekstensi tidak valid di sana karena harus di kelasnya sendiri. Solusi ini bisa bersifat pribadi dan tertanam di kelas lain.

Asher Garland
sumber
2

Saya kebetulan adalah penggemar VB.NET, jadi inilah versi saya, yang menggabungkan metode DescriptionAttribute dengan metode ekstensi. Pertama, hasilnya:

Imports System.ComponentModel ' For <Description>

Module Module1
  ''' <summary>
  ''' An Enum type with three values and descriptions
  ''' </summary>
  Public Enum EnumType
    <Description("One")>
    V1 = 1

    ' This one has no description
    V2 = 2

    <Description("Three")>
    V3 = 3
  End Enum

  Sub Main()
    ' Description method is an extension in EnumExtensions
    For Each v As EnumType In [Enum].GetValues(GetType(EnumType))
      Console.WriteLine("Enum {0} has value {1} and description {2}",
        v,
        CInt(v),
        v.Description
      )
    Next
    ' Output:
    ' Enum V1 has value 1 and description One
    ' Enum V2 has value 2 and description V2
    ' Enum V3 has value 3 and description Three
  End Sub
End Module

Hal-hal dasar: enum yang disebut EnumType dengan tiga nilai V1, V2 dan V3. "Magic" terjadi di panggilan Console.WriteLine di Sub Main (), di mana argumen terakhirnya sederhana v.Description. Ini mengembalikan "Satu" untuk V1, "V2" untuk V2, dan "Tiga" untuk V3. Metode Deskripsi ini sebenarnya adalah metode ekstensi, didefinisikan dalam modul lain yang disebut EnumExtensions:

Option Strict On
Option Explicit On
Option Infer Off

Imports System.Runtime.CompilerServices
Imports System.Reflection
Imports System.ComponentModel

Module EnumExtensions
  Private _Descriptions As New Dictionary(Of String, String)

  ''' <summary>
  ''' This extension method adds a Description method
  ''' to all enum members. The result of the method is the
  ''' value of the Description attribute if present, else
  ''' the normal ToString() representation of the enum value.
  ''' </summary>
  <Extension>
  Public Function Description(e As [Enum]) As String
    ' Get the type of the enum
    Dim enumType As Type = e.GetType()
    ' Get the name of the enum value
    Dim name As String = e.ToString()

    ' Construct a full name for this enum value
    Dim fullName As String = enumType.FullName + "." + name

    ' See if we have looked it up earlier
    Dim enumDescription As String = Nothing
    If _Descriptions.TryGetValue(fullName, enumDescription) Then
      ' Yes we have - return previous value
      Return enumDescription
    End If

    ' Find the value of the Description attribute on this enum value
    Dim members As MemberInfo() = enumType.GetMember(name)
    If members IsNot Nothing AndAlso members.Length > 0 Then
      Dim descriptions() As Object = members(0).GetCustomAttributes(GetType(DescriptionAttribute), False)
      If descriptions IsNot Nothing AndAlso descriptions.Length > 0 Then
        ' Set name to description found
        name = DirectCast(descriptions(0), DescriptionAttribute).Description
      End If
    End If

    ' Save the name in the dictionary:
    _Descriptions.Add(fullName, name)

    ' Return the name
    Return name
  End Function
End Module

Karena mencari atribut deskripsi menggunakan Reflectionlambat, pencarian juga di-cache di pribadiDictionary , yang diisi berdasarkan permintaan.

(Maaf untuk solusi VB.NET - seharusnya relatif lebih mudah untuk menerjemahkannya ke C #, dan C # saya berkarat pada subjek baru seperti ekstensi)

MarkusT
sumber
2

Bersihkan ringkasan saran di atas dengan sampel:

namespace EnumExtensions {

using System;
using System.Reflection;

public class TextAttribute : Attribute {
   public string Text;
   public TextAttribute( string text ) {
      Text = text;
   }//ctor
}// class TextAttribute

public static class EnumExtender {

public static string ToText( this Enum enumeration ) {

   MemberInfo[] memberInfo = enumeration.GetType().GetMember( enumeration.ToString() );

   if ( memberInfo != null && memberInfo.Length > 0 ) {

      object[] attributes = memberInfo[ 0 ].GetCustomAttributes( typeof(TextAttribute),  false );

      if ( attributes != null && attributes.Length > 0 ) {
         return ( (TextAttribute)attributes[ 0 ] ).Text;
      }

   }//if

   return enumeration.ToString();

}//ToText

}//class EnumExtender

}//namespace

PEMAKAIAN:

using System;
using EnumExtensions;

class Program {

public enum Appearance {

  [Text( "left-handed" ) ]
  Left,

  [Text( "right-handed" ) ]
  Right,

}//enum

static void Main( string[] args ) {

   var appearance = Appearance.Left;
   Console.WriteLine( appearance.ToText() );

}//Main

}//class
menggarisbawahi
sumber
1
Ada atribut [Keterangan ("")] di C #, mengapa tidak menggunakan ini?
Stefan Koenen
Tentu saja menggunakan [Deskripsi ("")] adalah cara yang harus dilakukan. Tapi saya ingin sampel lengkap.
garis bawah
2

Gunakan Enum.GetName

Dari tautan di atas ...

using System;

public class GetNameTest {
    enum Colors { Red, Green, Blue, Yellow };
    enum Styles { Plaid, Striped, Tartan, Corduroy };

    public static void Main() {

        Console.WriteLine("The 4th value of the Colors Enum is {0}", Enum.GetName(typeof(Colors), 3));
        Console.WriteLine("The 4th value of the Styles Enum is {0}", Enum.GetName(typeof(Styles), 3));
    }
}
// The example displays the following output:
//       The 4th value of the Colors Enum is Yellow
//       The 4th value of the Styles Enum is Corduroy
JMH
sumber
2

Menurut dokumentasi ini: https://docs.microsoft.com/pt-br/dotnet/api/system.enum.tostring?view=netframework-4.8

Dimungkinkan untuk mengonversi enumerator menjadi string menggunakan format seperti ini:

public enum Example
{
    Example1,
    Example2
}

Console.WriteLine(Example.Example1.ToString("g"));

//Outputs: "Example1"

Anda dapat melihat semua format yang mungkin di tautan ini: https://docs.microsoft.com/pt-br/dotnet/api/system.string?view=netframework-4.8

Emanuel Hiroshi
sumber
1

Ini adalah pembaruan untuk kode Ray Booysen yang menggunakan metode GetCustomAttributes generik dan LINQ untuk membuat hal-hal sedikit lebih rapi.

    /// <summary>
    /// Gets the value of the <see cref="T:System.ComponentModel.DescriptionAttribute"/> on an struct, including enums.  
    /// </summary>
    /// <typeparam name="T">The type of the struct.</typeparam>
    /// <param name="enumerationValue">A value of type <see cref="T:System.Enum"/></param>
    /// <returns>If the struct has a Description attribute, this method returns the description.  Otherwise it just calls ToString() on the struct.</returns>
    /// <remarks>Based on http://stackoverflow.com/questions/479410/enum-tostring/479417#479417, but useful for any struct.</remarks>
    public static string GetDescription<T>(this T enumerationValue) where T : struct
    {
        return enumerationValue.GetType().GetMember(enumerationValue.ToString())
                .SelectMany(mi => mi.GetCustomAttributes<DescriptionAttribute>(false),
                    (mi, ca) => ca.Description)
                .FirstOrDefault() ?? enumerationValue.ToString();
    }   
Richard Anthony Hein
sumber
Gagal melihat mengapa Anda membutuhkannya untuk menjadi generik? Jika Anda akan menggunakan refleksi?
Lee Louviere
@LeeLouviere Terutama untuk menghindari tinju ketika struct (tipe nilai) diteruskan sebagai parameter.
Richard Anthony Hein
1
alih-alih numerationValue.GetType () gunakan: typeof (T).
Slava
1
Peningkatan satu baris besar atas jawaban yang diterima tanpa (YMMV) kehilangan keterbacaan. Ya, dengan typeof (T).
TonyG
1

Ringkasan yang lebih bersih:

using System;
using System.Reflection;

public class TextAttribute : Attribute
{
    public string Text;
    public TextAttribute(string text)
    {
        Text = text;
    }
}  

public static class EnumExtender
{
    public static string ToText(this Enum enumeration)
    {
        var memberInfo = enumeration.GetType().GetMember(enumeration.ToString());
        if (memberInfo.Length <= 0) return enumeration.ToString();

        var attributes = memberInfo[0].GetCustomAttributes(typeof(TextAttribute), false);
        return attributes.Length > 0 ? ((TextAttribute)attributes[0]).Text : enumeration.ToString();
    }
}

Penggunaan yang sama dengan yang digambarkan garis bawah.

StefanDK
sumber
0

Untuk bendera termasuk enum.

    public static string Description(this Enum value)
    {
        Type type = value.GetType();

        List<string> res = new List<string>();
        var arrValue = value.ToString().Split(',').Select(v=>v.Trim());
        foreach (string strValue in arrValue)
        {
            MemberInfo[] memberInfo = type.GetMember(strValue);
            if (memberInfo != null && memberInfo.Length > 0)
            {
                object[] attrs = memberInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);

                if (attrs != null && attrs.Length > 0 && attrs.Where(t => t.GetType() == typeof(DescriptionAttribute)).FirstOrDefault() != null)
                {
                    res.Add(((DescriptionAttribute)attrs.Where(t => t.GetType() == typeof(DescriptionAttribute)).FirstOrDefault()).Description);
                }
                else
                    res.Add(strValue);
            }
            else
                res.Add(strValue);
        }

        return res.Aggregate((s,v)=>s+", "+v);
    }
Lukich
sumber
0

Jika Anda hanya ingin menambahkan spasi putih di antara kata-kata, sesederhana itu

string res = Regex.Replace(PublishStatusses.NotCompleted, "[A-Z]", " $0").Trim();
VladL
sumber
0

Saya menggunakan kelas generik untuk menyimpan pasangan enum / deskripsi dan kelas penolong bersarang untuk mendapatkan deskripsi.

The enum :

enum Status { Success, Fail, Pending }

Kelas generik:

Catatan: Karena kelas generik tidak dapat dibatasi oleh enum saya dibatasi oleh struct sebagai gantinya dan memeriksa enum di konstruktor.

public class EnumX<T> where T : struct
{
    public T Code { get; set; }
    public string Description { get; set; }

    public EnumX(T code, string desc)
    {
        if (!typeof(T).IsEnum) throw new NotImplementedException();

        Code = code;
        Description = desc;
    }

    public class Helper
    {
        private List<EnumX<T>> codes;

        public Helper(List<EnumX<T>> codes)
        {
            this.codes = codes;
        }

        public string GetDescription(T code)
        {
            EnumX<T> e = codes.Where(c => c.Code.Equals(code)).FirstOrDefault();
            return e is null ? "Undefined" : e.Description;
        }
    }
}

Pemakaian:

EnumX<Status>.Helper StatusCodes = new EnumX<Status>.Helper(new List<EnumX<Status>>()
        {
            new EnumX<Status>(Status.Success,"Operation was successful"),
            new EnumX<Status>(Status.Fail,"Operation failed"),
            new EnumX<Status>(Status.Pending,"Operation not complete. Please wait...")
        });

        Console.WriteLine(StatusCodes.GetDescription(Status.Pending));
zisha
sumber
-2

Saya pikir cara terbaik (dan termudah) untuk menyelesaikan masalah Anda adalah dengan menulis Extension-Method untuk enum Anda:

public static string GetUserFriendlyString(this PublishStatusses status)
    {

    }
pengguna7096584
sumber
1
Seseorang 7 tahun sebelumnya menyatakan bahwa
Steven