ユーザーフレンドリーな文字列を持つ列挙型ToString


回答:


350

DescriptionSystem.ComponentModel名前空間の属性を使用します。列挙型を単に飾る:

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

次に、このコードを使用してそれを取得します。

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
この例は読みやすいです。 stackoverflow.com/questions/1415140/...
RayLoveless

31
このソリューションで説明されているように、リフレクションを使用するとパフォーマンスに大きな影響があると思います。ToFriendlyString拡張メソッドを使用するWillのメソッドのコードは、はるかに理解しやすく、パフォーマンスも非常に高速です。
humbads 14

1
Enumsに拡張メソッドを追加するだけなので、@ RayLがリンクしたバージョンが好きです。それはあなたがこれを使用したいすべてだ場合に示されているように(ArgumentException、この方法は完全に汎用的なもの持っている理由はありません。
krillgar

4
これは、すべての列挙型が独自の拡張メソッドを必要とすることを意味します。これはより一般的な使用法であり、より多くの作業が必要ですが、パフォーマンスを決定する前に、「高速」の意味を数値化したいと思うでしょう。
レイブイセン2015年

2
@petarは機能しますが、わかりやすい文字列をユーザーに表示したい場合は機能しません。MY_TYPEには下線が付き、カスタマイズできません。
Ray Booysen

354

私はこれを拡張メソッドで行います:

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
これは属性の回答よりもはるかにきれいです。いいね!
pennyrave

3
@pennyrave:ええ。多くのUIコンポーネントは、DisplayNameAttributeとDescriptionAttributeを見つけて使用することを期待しています。実際、今、これらと拡張メソッドを使用して、これらの値を簡単に取得しています。

60
これで私が目にする問題は、あなたが常にこれらの拡張メソッドを書いているということです。属性メカニズムを使用すると、それを修飾して、1つのメソッドを呼び出すだけの簡単な方法になります。
Ray Booysen、2014年

5
よく分からない?
Ray Booysen 2014年

9
私の意見では、defaultcase実装が戻りme.ToString()、オーバーライドしたい列挙値に対してのみswitch caseステートメントを提供できるようにする方が良いと思います。あなたの例では、それらはすべて異なることがわかりますが、実際の使用例では、単一単語の列挙値のほとんどで十分であり、複数単語の列挙値のオーバーライドのみを提供していると思います。
スコット

78

何か足りないのかもしれませんが、Enum.GetNameの何が問題になっていますか?

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

編集:ユーザーフレンドリーな文字列の場合、国際化/ローカライズを行うには.resourceを通過する必要があります。おそらく、同じデコレーター属性よりもenumキーに基づく固定キーを使用する方が良いでしょう。


11
ユーザーフレンドリーではなく、列挙型のリテラル値を返します。
Boris Callens、

2
OIC -まあ、代替(デコレータはattribs)はI18Nをサポートしていますので、あなたは、この値に基づいて文字列リソースライブラリを通過する必要があることかなり大きな場合があります
annakata

1
I18Nの場合、翻訳された文字列をリソースライブラリでGetDescription()メソッドで検索し、説明にフォールバックしてから、リテラルにフォールバックします。
Boris Callens、

3
ローカリゼーションのリソースキーとしてのMyEnum.ToString()の+1。私は何年もそうしています
jackvsworld 2013

1
@annakataは実際に属性メカニズムを拡張してl18Nのサポートを含めました。これは実際には単純な変更です。
Ray Booysen、2014年

23

説明を列挙値に戻すための逆拡張メソッドを作成しました。

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
申し訳ありませんが、お役に立ててありがとうございます。こちらはQ&Aサイトですので、回答直接質問に答える試みでなければなりません。そして質問は、具体的には、「述べて私は再び値に文字列から行くことができるようにする必要がありません。」もう一度、感謝を!
ジェシー

8
肯定的な批判をありがとう。サイトを初めて利用し、その文化やニュアンスについて学ぶことは常に困難です。あなたのような新しい人たちをまっすぐに設定してくれる人がいてうれしいです。もう一度、新しい男を捨てないでくれてありがとう。
ブライアンリチャードソン

6
@Jesseそして4年後、誰かがここでbjrichardsonコードを見つけて喜んでいます!SOはQ&Aサイトかもしれませんが、質問が回答された後に死んでいるという意味ではありません。
John

18

ここで最も簡単な解決策は、カスタム拡張メソッドを使用することです(少なくとも.NET 3.5では-以前のフレームワークバージョンの静的ヘルパーメソッドに変換することができます)。

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

ここでは、列挙値の実際の名前(単にToStringを呼び出すだけで取得できる)以外のものを返したいと想定しています。


有効ですが、属性の方がずっと好きです。このようにして、カスタムの文字列表現をenum自体に入れながら、toSTringメソッドを別のライブラリーに入れることができます
Boris Callens

1
けっこうだ。このメソッドの1つの利点は、いくつかの状態変数を指定するメソッドに引数を含め、これに応じて返される文字列表現を変更できることです。
ノルドリン2009年

1
はい、それはすべて私が推測する方法の範囲に依存します。属性の方法はより一般的ですが、ソリューションはよりローカライズされています。結局のところ、それはすべてニーズに関するものです。
Boris Callens、

1
拡張メソッドはどこにでも配置できます。それらを使用する場所で参照する必要があります。

はい、ただし、これは、わかりやすい名前を付けたい新しい列挙型を導入するたびに、この1つの拡張メソッドを書き直す必要があることを意味します。これは、すべてのアプリケーションが他のすべてのアプリケーションのフレンドリ名を持ち運ぶことも意味します...
Boris Callens

13

その別の投稿はJavaです。C#のEnumにメソッドを配置することはできません。

次のようなことをしてください:

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

列挙値に異なる表示値を使用する場合は、属性とリフレクションを使用できます。


3
toStringはすべての場合において安全ではありません-同じ値(たとえば、整数列挙型)を持つ複数のエントリを持つ列挙型は、テストされた項目のキーではなく、最初に一致する値のキーを返します。これがEnum.GetNameが推奨される理由です
アナカタ09年

4
まあそれは彼の特定の列挙型にとって最も簡単な解決策でした
Lemmy

9

最も簡単な方法は、この拡張クラスをプロジェクトに含めるだけで、プロジェクト内のすべての列挙型で機能します。

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

使用法:

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

...

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

2
なぜこのコメントが受け入れられないのか、または最も賛成されないのかは不思議です。反映も不要な属性もないため、列挙型がすでに適切に名前付けされている単純な状況に最適です。この答えをさらに一歩進めて、「My Enum」を返す前に大文字の間にスペースを追加することができます。
Vix

12
enumがすでに適切に名前が付けられている場合、拡張メソッドは必要ありません。既存のToString()メソッドを使用するだけです。string result = "Result: " + ee;
John

これが最良の答えです。任意の列挙型で機能します。パラメータのEnum型を実際に使用する実際のEnumに変更するだけで、特定のEnumを使用して実装することもできます。
Juanu Haedo 2016

6
この回答とすべてのコメントは、拡張された説明に対する元の要求を無視します。皆さんは、デフォルトのToString値以外のものを返すという演習を完全に失敗しました。ここでは、この回答のすべてのメモに反対票を投じませんが、必ず反対票を投じます。
TonyG 2017年

8

クラス/参照タイプを回避するいくつかの他のより基本的なオプション:

  • 配列方式
  • ネストされた構造体メソッド

配列方式

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

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

使用法

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

ネストされた構造体メソッド

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

使用法

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

アップデート(03/09/2018)

拡張メソッドと上記の最初の手法のハイブリッド。

私は列挙型がそれらが「属する」場所で定義されることを好みます(それらの起源のソースに最も近く、いくつかの一般的なグローバル名前空間ではありません)。

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

拡張メソッドは共通領域に適しているようで、列挙型の「ローカライズされた」定義により、拡張メソッドがより冗長になりました。

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

列挙型とその拡張メソッドの使用例。

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

注:実際にはEnumラッパー(およびName配列)を排除することにしました。名前の文字列はハードコードするのではなく、リソース(つまり、構成ファイルまたはDB)から取得するのが最善であり、拡張メソッドをViewModels名前空間(別の「CommonVM.cs」ファイルにある)。加えて、すべて.Idが気を散らして面倒になります。

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

列挙型とその拡張メソッドの使用例。

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投票:このソリューションはEnum構文を保持し、リフレクションや複雑なコードなしで問題をエレガントに解決するため、+ 1します。ただし、Enum自体の機能は失われます。したがって、IMOはこれは適切なオプションですが、実際の質問には答えず、-1を取得します。ネット0。申し訳ありませんが、SOでそれをよりよく記録する方法はありません。
TonyG 2017年

@TonyG十分だ。pluarlsight.comの.netスキルの評価に関するいくつかの質問を見逃した後、C#列挙型の詳細を理解し始めたので、適用する方法を決定する前に、少なくともそれらの機能を知っておくことをお勧めします(特に、広範囲にわたる使用、リファクタリングの場合)。少し時間がかかることがあります;)。
samis 2017年

7

Humanize Enumsの可能性があるHumanizerパッケージを使用できます。簡単な例:

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

次にHumanize、列挙型で直接拡張メソッドを使用できます。

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)

リフレクションも使用し、キャッシュされません。github.com/Humanizr/Humanizer/blob/...
コンラート

レイの最初の回答の解決策と同じくらい遅くなります
Konrad、

5

Ray Booysenに関しては、コードにバグがあります:ユーザーフレンドリーな文字列を含むEnum ToString

列挙値の複数の属性を考慮する必要があります。

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
複数のDescription属性のチェックの省略は意図的なものです。enumに2つあり、説明の生成に使用している場合、それは例外的な状況だと思います。実際のバグは、例外がスローされるようにSingle()を実行していないことだと思います。それ以外の場合、メソッドシグネチャ全体は意味がありません。GetDescription()?どの説明?集計?
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
なぜこれがうまくいくのか、なぜOPがうまくいかないのかを説明するテキストを書くのはいつもいいことです。
ファベレスト

参考までに、C#のコード規則では、ローカル変数とメソッドパラメータに小文字の頭文字を付ける必要があります。1つの例外は、Webの多くの例でthis呼び出さThisれていることがわかる拡張メソッドのパラメーターです。(Enum Enum)のようにその型のように呼び出すと、コードが読みにくくなります。
Massimiliano Kraus

4

列挙型を使用する代わりに、静的クラスを使用します。

取り替える

private enum PublishStatuses{
    NotCompleted,
    Completed,
    Error
};

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

このように使用されます

PublishStatuses.NotCompleted; // "Not Completed"

上位の「拡張方法」ソリューションを使用した問題:

多くの場合、プライベート列挙は別のクラス内で使用されます。拡張メソッドソリューションは、それ自体のクラスに存在する必要があるため、そこでは無効です。このソリューションはプライベートで、別のクラスに組み込むことができます。


2

私はたまたまVB.NETのファンなので、DescriptionAttributeメソッドと拡張メソッドを組み合わせた私のバージョンです。まず、結果:

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

基本的なもの:3つの値V1、V2、V3を持つEnumTypeと呼ばれる列挙型。「マジック」は、Sub Main()のConsole.WriteLine呼び出しで発生しv.Descriptionます。最後の引数は単にです。これは、V1の場合は「One」、V2の場合は「V2」、V3の場合は「Three」を返します。このDescriptionメソッドは、実際には拡張メソッドであり、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

を使用して説明属性をReflection検索するのが遅いため、検索もプライベートにキャッシュされますDictionaryオンデマンドで入力さ。

(VB.NETソリューションについて申し訳ありません-C#に変換するのは比較的簡単なはずです。私のC#は拡張機能などの新しいテーマで錆びています)


2

上記の提案とサンプルの明確な要約:

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

使用法:

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#には[Description( "")]属性があります。これを使用しないのはなぜですか?
Stefan Koenen

もちろん、[Description( "")]を使用する方法もあります。しかし、サンプルを完成させたかったのです。
下線

2

Enum.GetNameを使用する

上記のリンクから...

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

2

このドキュメントによると:https : //docs.microsoft.com/pt-br/dotnet/api/system.enum.tostring?view=netframework-4.8

次のような形式を使用して、列挙子を文字列に変換するだけです。

public enum Example
{
    Example1,
    Example2
}

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

//Outputs: "Example1"

あなたはこのリンクですべての可能なフォーマットを見ることができます: https //docs.microsoft.com/pt-br/dotnet/api/system.string?view=netframework-4.8


1

これは、汎用的なGetCustomAttributesメソッドとLINQを使用して物事を少し整頓するRay Booysenのコードの更新です。

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

なぜあなたはそれが一般的である必要があるのか​​を見落としていますか?リフレクションを使用する場合は、
イルビエール2013

@LeeLouviere主に構造体(値の型)がパラメーターとして渡されるときにボクシングを回避します。
Richard Anthony Hein 2013

1
代わりに、numerationValue.GetType()を使用してください:typeof(T)。
スラバ2017年

1
(YMMV)可読性を失うことなく、受け入れられた回答を大幅に1行改善。はい、typeof(T)を使用します。
TonyG 2017年

1

より明確な要約:

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

アンダースコアが説明するのと同じ使用法。


0

フラグ列挙型を含む。

    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

単語間に空白を追加するだけの場合は、次のように簡単です。

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

0

ジェネリッククラスを使用して列挙型と説明のペアを格納し、ネストされたヘルパークラスを使用して説明を取得します。

列挙型

enum Status { Success, Fail, Pending }

ジェネリッククラス:

注:ジェネリッククラスは列挙型で制約できないため、代わりにstructで制約し、コンストラクターで列挙型をチェックしています。

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

使用法:

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

私はあなたの問題を解決する最良の(そして最も簡単な)方法はあなたの列挙型のExtension-Methodを書くことだと思います:

public static string GetUserFriendlyString(this PublishStatusses status)
    {

    }

1
誰かが7年前にそれを述べた
Steven

-3

完全にカスタマイズ可能なものが必要な場合は、ここで私の解決策を試してください:

http://www.kevinwilliampang.com/post/Mapping-Enums-To-Strings-and-Strings-to-Enums-in-NET.aspx

基本的に、この投稿では、説明属性を各列挙型にアタッチする方法の概要を説明し、列挙型から説明にマッピングする一般的な方法を提供します。


1
そして今、サイトはダウンしています。
Nic Foster、
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.