Kullanıcı dostu dizelerle Enum ToString


Yanıtlar:


350

DescriptionSystem.ComponentModel ad alanından özniteliği kullanıyorum . Numaralandırmayı süsleyin:

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

Sonra almak için bu kodu kullanın:

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

12
Bu örneğin okunması daha kolaydır. stackoverflow.com/questions/1415140/…
RayLoveless

31
Bu çözümde açıklanan yansımayı kullanmak için önemli bir performans artışı olduğundan şüpheleniyorum. Will'in ToFriendlyString uzantı yöntemini kullanma yönteminin kodunu anlamak çok daha kolaydır ve performansı da son derece hızlı olmalıdır.
humbad

1
@RayL, yalnızca Numaralandırmalar için eklenti yöntemi ekleyeceği gibi bağlı sürümü seviyorum. Bunu kullanmak istediğiniz tek şey buysa (ile gösterildiği ArgumentExceptiongibi, yöntemin tamamen genel olması için bir neden yoktur.
krillgar

4
Her numaralandırmanın kendi genişletme yöntemine ihtiyacı olduğu anlamına gelir. Bu daha genel bir kullanımdır ve daha fazla çalışma gerektirir, ancak muhtemelen performansa karar vermeden önce "hızlı" nın ne anlama geldiğini ölçmek istersiniz.
Ray Booysen

2
@petar çalışır, ancak kullanıcılara dost dizelerin görüntülenmesini istiyorsanız değil. MY_TYPE alt çizgiye sahip olacak ve özelleştirilemez.
Ray Booysen

354

Bunu uzantı yöntemleri ile yapıyorum:

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

6
Bu, Nitelik yanıtından çok daha temizdir. Güzel!
pennyrave

3
@pennyrave: Eh. Birçok UI bileşeni DisplayNameAttribute ve DescriptionAttribute'ı bulmayı ve kullanmayı bekliyor. Aslında, şimdi, bu değerleri kolayca elde etmek için bunları ve bir uzantı yöntemini kullanıyorum.

60
Bununla ilgili gördüğüm sorun, bu uzantı yöntemlerini sürekli olarak yazmanızdır. Nitelik mekanizması ile, onu süslemenin basit bir yolu ve sadece bir yöntem çağırmak.
Ray Booysen

5
Ne demek istediğinden emin değilim?
Ray Booysen

9
Bence defaultvaka uygulamasının geri dönmesine izin vermek me.ToString()ve yalnızca geçersiz kılmak istediğiniz numaralandırma değerleri için anahtar durum ifadeleri sağlamak daha iyidir . Örneğinizde, hepsinin farklı olduğunu anlıyorum, ancak gerçek kullanım durumlarında, tek kelimelik numaralandırma değerlerinin çoğunun yeterli olacağından ve yalnızca çok kelimeli numaralandırma değerleri için geçersiz kılmalar sağlayacağınızdan şüpheleniyorum.
Scott

78

Belki bir şey eksik, ama Enum.GetName ile sorun nedir?

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

edit: kullanıcı dostu dizeler için, uluslararasılaştırma / yerelleştirme yapmak için bir .resource geçmeniz gerekir ve aynı zamanda bir dekoratör özniteliği yerine enum anahtarına dayalı sabit bir anahtar kullanmak daha iyi olurdu.


12
Bazı kullanıcı dostu değil, enum gerçek değeri döndürür.
Boris Callens

2
oic - o zaman bu değere dayalı bir dize kaynak kütüphanesinden geçmeniz gereken oldukça büyük bir durum var, çünkü alternatif (dekoratör attribs)
I18N'yi

1
I18N durumunda, GetDescription () yönteminin kaynak lib'de çevrilmiş bir dize aramasını ve açıklamaya geri dönmesini ve ardından değişmez kelimeye geri dönmesini sağlardım.
Boris Callens

3
Yerelleştirme için kaynak anahtarı olarak MyEnum.ToString () için +1. Bunu yıllardır yapıyorum
jackvsworld

1
@annakata aslında öznitelik mekanizmasını l18N için destek içerecek şekilde genişlettik, aslında basit bir değişiklik.
Ray Booysen

23

Açıklamayı tekrar bir enum değerine dönüştürmek için bir ters uzantısı yöntemi oluşturdum:

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

15
Üzgünüm, ama yardımcı olmaya çalıştığınız için teşekkürler! Bu bir Soru-Cevap sitesi olduğu için, cevaplar soruyu doğrudan cevaplamaya yönelik bir girişim olmalıdır . Ve soru özellikle " tekrar dizeden değere gitmek mümkün değil " diyor . Bir kez daha teşekkürler!
Jesse

8
Olumlu eleştiri için teşekkürler. Bir site için yeni olmak ve kültürü ve nüansları hakkında bilgi edinmek her zaman zordur. Senin gibi yeni adamları düzleştiren insanlar olduğuna sevindim. Bir kez daha, yeni adama basmadığın için teşekkürler.
Brian Richardson

6
@Jesse Ve 4 yıl sonra birisi burada bjrichardson kodunu bulmaktan mutluluk duyar! SO bir Soru-Cevap sitesi olabilir, ancak soruların cevaplandıktan sonra öldüğü anlamına gelmez.
John

18

Buradaki en kolay çözüm, özel bir uzantı yöntemi kullanmaktır (en azından .NET 3.5'te - bunu önceki çerçeve sürümleri için statik bir yardımcı yönteme dönüştürebilirsiniz).

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

Burada (sadece ToString çağırarak alabilirsiniz) enum değeri gerçek adı dışında bir şey döndürmek istediğiniz varsayıyorum.


Geçerli olmasına rağmen, bu özelliği daha çok seviyorum. Bu şekilde, tostring yöntemimi ayrı bir kütüphaneye koyabilirken, numaralandırma ile özel dize temsilini koyabilirim
Boris Callens

1
Yeterince adil. Bu yöntemin bir avantajı bazı durum değişkeni belirleme yöntemi ile bir argüman eklemek ve daha sonra buna bağlı olarak dize temsil döndürülen değiştirmek olduğunu varsayalım.
Noldorin

1
Evet, hepsi sanırım yöntemin kapsamına bağlı. Öznitelik yolu daha genel olsa da, çözümünüz daha yereldir.
Boris Callens

1
Uzantı yöntemlerini istediğiniz yere koyabilirsiniz. Sadece kullanmak istediğiniz yere başvurmanız gerekir.

Evet, ancak bu, kolay bir isme sahip olmak istediğiniz her yeni numarayı her tanıttığınızda bu bir uzatma yönteminin yeniden yazılması gerektiği anlamına gelir. Bu ayrıca, TÜM uygulamalarınızın TÜM diğer uygulamalarınız için kolay adlar taşıyacağı anlamına gelir ...
Boris Callens

13

Bu diğer yazı Java. C # 'daki Numaralandırmalara yöntem koyamazsınız.

sadece böyle bir şey yapın:

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

Numaralandırma değerleriniz için farklı görüntüleme değerleri kullanmak istiyorsanız, Öznitelikler ve Yansıma kullanabilirsiniz.


3
toString her durumda güvenli değildir - aynı değere sahip birden fazla girişi olan bir enum (tamsayı numaralandırmalar için diyelim) test edilen öğenin anahtarı değil, ilk eşleşen değerin anahtarını döndürür, bu nedenle Enum.GetName tercih edilir
09:20

4
Peki enum için en kolay çözümdü
Lemmy

9

En basit yol sadece bu uzantı sınıfını projenize dahil etmektir, projedeki herhangi bir numaralandırma ile çalışacaktır:

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

Kullanımı:

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

...

ExampleEnum ee = ExampleEnum.Live;
Console.WriteLine(ee.ToFriendlyString());

2
Bu yorumun neden kabul edilen veya en çok oylanan olmadığı bir gizemdir - yansıma yok, gereksiz özellik yok, enumun zaten güzel bir şekilde adlandırıldığı basit durumlar için idealdir. Bu yanıtı bir adım daha ileri taşıyabilir ve 'Enum'um'a dönmeden önce büyük harfler arasına boşluklar ekleyebilirsiniz.
Vix

12
Numaralandırma zaten güzel bir şekilde adlandırılmışsa, herhangi bir uzantı yöntemine gerek yoktur. Sadece mevcut ToString () yöntemini kullanın. string result = "Result: " + ee;
John

Bu en iyi cevap olmalı. Herhangi bir numaralandırma için çalışır. Hatta, parametrenin Enum türünü, kullanılacak Enum Enum ile değiştirerek belirli Enum kullanarak da uygulayabilirsiniz.
Juanu Haedo

6
Bu yanıt ve tüm yorumlar, genişletilmiş açıklama için orijinal isteği yok sayar. Varsayılan ToString değerinden başka bir şey döndürecek olan egzersizi tamamen kaçırdınız. Burada bu cevaba ilişkin tüm notları küçümsemeyeceğim ama kesinlikle istiyorum.
TonyG

8

Sınıfları / referans türlerini önleyen bazı daha ilkel seçenekler:

  • Dizi yöntemi
  • İç içe yapı yöntemi

Dizi yöntemi

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

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

kullanım

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

İç içe yapı yöntemi

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

kullanım

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

Güncelleme (03/09/2018)

Bir Genişleme Yöntemleri melezi ve yukarıdaki ilk teknik.

Enumların, "ait oldukları" (tanım kaynaklarına en yakın ve bazı ortak, küresel ad alanlarında değil) tanımlanmasını tercih ederim.

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

Genişletme yöntemi ortak bir alan için uygun görünmektedir ve enumun "lokalize" tanımı artık genişletme yöntemini daha ayrıntılı hale getirmektedir.

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

Enum ve onun uzatma yönteminin kullanım örneği.

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

Not: Aslında Enumsarıcı (ve Namedizi) ortadan kaldırmaya karar verdim , çünkü isim dizelerinin sabit kodlu olmak yerine bir kaynaktan (yani config dosyası veya DB) gelmesi en iyisidir ve uzantı yöntemini ViewModelsad alanı (yalnızca farklı bir "CommonVM.cs" dosyasında). Ayrıca her .Idşey dikkat dağıtıcı ve hantal hale gelir.

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

Enum ve onun uzatma yönteminin kullanım örneği.

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

+ 1-1 = 0 oy: Bu çözüm Enum sözdizimini korur ve sorunu yansıma veya karmaşık kod olmadan zarif bir şekilde çözer, bu yüzden orada +1. Ancak Enum'ların özelliklerini kaybeder. IMO bu iyi bir seçenek olsa da, asıl soruya cevap vermez ve -1 alır. Net 0. Üzgünüz, bunu SO'da daha iyi kaydetmenin bir yolu yok.
TonyG

@TonyG Yeterince adil. Pluarlsight.com'un .net beceri değerlendirmesiyle ilgili birkaç sorudan sonra C # enum'un ne kadar derin olduğunu anlamaya başladım, bu yüzden hangi yöntemin uygulanacağına karar vermeden önce en azından yeteneklerini bilmek iyi bir fikirdir (özellikle yaygın kullanım, yeniden düzenleme için) biraz zaman olabilir;).
samis

7

Humanizer paketini Humanize Enums olasılığı ile kullanabilirsiniz . Bir örnek:

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

Humanizedoğrudan numaralandırmada uzantı yöntemini kullanabilirsiniz :

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)

Yansımayı da kullanır ve önbelleğe alınmaz. github.com/Humanizr/Humanizer/blob/…
Konrad

Ray'ın ilk cevabındaki çözüm kadar yavaş olacak
Konrad

5

Ray Booysen ile ilgili olarak, kodda bir hata var: Kullanıcı dostu dizelerle Enum ToString

Enum değerlerinde birden çok özelliği hesaba katmanız gerekir.

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

4
Birden çok Açıklama özelliği için bir denetimin atlanması bilerek yapılmıştır. Numaralandırma iki varsa ve bir açıklama oluşturmak için kullanıyorsanız, bunun olağanüstü bir durum olduğunu düşünmek istiyorum. Asıl hata, bir istisna atılmış bir Single () yapmıyorum olduğunu düşünüyorum. Aksi takdirde, tüm yöntem imzası bir anlam ifade etmez. GetDescription ()? Hangi açıklama? Toplu mı?
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;
}

3
Bunun neden çalışması gerektiğini ve OP'lerin neden işe yaramadığını açıklayan bir metin yazmak her zaman iyidir.
phaberest

Sadece FYI, C # kod kuralları yerel değişkenleri ve küçük harf ilk harfiyle yöntem parametrelerini ister. Bir istisna, web'deki birçok örnekte thisçağrıldığını görebileceğiniz uzantı yöntemlerindeki parametredir This. Bunu yaptığınız gibi çağırmak ( Enum Enum) kodu daha az okunabilir hale getirir.
Massimiliano Kraus

4

Bir enum kullanmak yerine statik bir sınıf kullanın.

değiştirmek

private enum PublishStatuses{
    NotCompleted,
    Completed,
    Error
};

ile

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

bu şekilde kullanılacak

PublishStatuses.NotCompleted; // "Not Completed"

En iyi "uzantı yöntemi" çözümlerini kullanarak sorun:

Özel bir numaralandırma genellikle başka bir sınıfın içinde kullanılır. Eklenti yöntemi çözümü, kendi sınıfında olması gerektiği için geçerli değildir. Bu çözüm özel olabilir ve başka bir sınıfa gömülebilir.


2

Bir VB.NET hayranı oldum, bu yüzden burada benim sürüm, DescriptionAttribute yöntemini bir uzantısı yöntemi ile birleştirerek. İlk olarak, sonuçlar:

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

Temel şeyler: Üç değer V1, V2 ve V3 olan EnumType adlı bir numaralandırma. "Büyü", son argümanın basit olduğu Sub Main () içindeki Console.WriteLine çağrısında gerçekleşir v.Description. Bu, V1 için "Bir", V2 için "V2" ve V3 için "Üç" değerini döndürür. Bu Description-yöntemi aslında EnumExtensions adlı başka bir modülde tanımlanan bir genişletme yöntemidir:

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

Kullanarak açıklama özniteliklerine bakmak Reflectionyavaş olduğundan, aramalar özel olarak da önbelleğe alınır ve Dictionarybu istek üzerine doldurulur.

(VB.NET çözümü için özür dilerim - C #'a çevirmek nispeten zor olmalı ve C # uzantıları gibi yeni konularda paslı)


2

Yukarıdaki önerilerin özetini örnekle temizleyin:

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

KULLANIM:

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

1
C # bir [Description ("")] özniteliği var, neden bunu kullanmıyorsunuz?
Stefan Koenen

Tabii ki [Açıklama ("")] kullanarak gitmek için bir yoldur. Ama numunenin tamamlanmasını istedim.
alt çizgi

2

Enum.GetName Kullan

Yukarıdaki linkten ...

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


1

Bu, işleri biraz daha düzenli hale getirmek için genel GetCustomAttributes yöntemini ve LINQ kullanan Ray Booysen kodunun bir güncellemesidir.

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

Niçin jenerik olması gerektiğini göremiyor musunuz? Yansımayı kullanacaksanız?
Lee Louviere

@LeeLouviere Temelde yapı (değer türü) parametre olarak iletildiğinde bokstan kaçınmak.
Richard Anthony Hein

1
bunun yerine numerationValue.GetType () kullanın: typeof (T).
Slava

1
(YMMV) okunabilirliğini kaybetmeden kabul edilen cevap üzerinde büyük bir satırlık iyileştirme. Evet, typeof (T) ile.
TonyG

1

Daha da temiz özet:

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

Alt çizgi ile aynı kullanım açıklanmaktadır.


0

Bayraklar için numaralandırma dahil.

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

0

Kelimeler arasına boşluk eklemek istiyorsanız, bu kadar basit

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

0

Enum / açıklama çiftlerini depolamak için genel bir sınıf ve açıklamayı almak için iç içe bir yardımcı sınıf kullanın.

enum :

enum Status { Success, Fail, Pending }

Genel sınıf:

Not: Genel bir sınıf bir enum tarafından sınırlanamadığından, bunun yerine struct ile kısıtlıyorum ve yapıcıda enum'u kontrol ediyorum .

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

Kullanımı:

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

-2

Sorununuzu çözmenin en iyi (ve en kolay) yolunun numaralandırmanız için bir Extension-Method yazmak olduğunu düşünüyorum:

public static string GetUserFriendlyString(this PublishStatusses status)
    {

    }

1
Birisi bunu belirtmek için 7 yıl önceydi
Steven

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.