341

私の列挙型は次の値で構成されています。

private enum PublishStatusses{
    NotCompleted,
    Completed,
    Error
};

ただし、これらの値をユーザーフレンドリーな方法で出力できるようにしたいと考えています。
文字列から値に再び移動できる必要はありません。

4

24 に答える 24

412

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();
}
于 2009-01-26T11:01:07.900 に答える
404

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

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!";
    }
  }
}
于 2009-01-26T11:15:25.623 に答える
96

多分私は何かが足りないのですが、Enum.GetName の何が問題なのですか?

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

編集: ユーザーフレンドリーな文字列の場合、国際化/ローカライズを行うには .resource を使用する必要があります。また、enum キーに基づいて固定キーを使用する方が、同じデコレーター属性よりも優れていると言えます。

于 2009-01-26T11:11:32.340 に答える
25

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

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");
}
于 2013-04-18T00:09:07.503 に答える
20

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

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

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

于 2009-01-26T11:03:20.827 に答える
13

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

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

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

列挙値に異なる表示値を使用する場合は、属性と反射を使用できます。

于 2009-01-26T11:03:01.170 に答える
8

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

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());
于 2015-02-03T21:26:04.943 に答える
6
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;
}
于 2016-02-23T14:41:12.027 に答える
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();
于 2009-04-30T20:51:35.573 に答える
3

サンプルを含む上記の提案の簡潔な要約:

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
于 2014-10-26T16:29:13.517 に答える
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-methodは実際には拡張メソッドであり、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#は拡張機能のような新しい主題で錆びています)

于 2013-02-08T11:55:10.080 に答える
2

さらにクリーンな要約:

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

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

于 2014-11-19T10:05:42.633 に答える
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();
    }   
于 2012-11-12T03:23:49.580 に答える
1

私はパーティーに 7 年遅れています :-) でも、このトピックは頻繁に訪れていると思います。
だから私はコーヒーに砂糖を少し加えたかった:

「F」フォーマット文字列指定子はどうですか?

PublishStatusses[] ps = Enum.GetValues<PublishStatusses>();
ps.ToList().ForEach(c => Console.Write($"{c:F} "));

明示的な関数呼び出しは必要ありません。

実際、フォーマット指定子も必要ありません。文字列への変数の代入の場合、ToString() が次のように機能します。

string foo = PublishStatusses.Error.ToString(); // or ToString("F")

また、キャメルケース文字列の単語間にスペースを挿入しようとしている場合は、正規表現を使用できます。

Regex.Replace(foo, "(\\B[A-Z])", " $1")
于 2021-07-26T19:46:15.550 に答える
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);
    }
于 2015-11-27T13:29:39.767 に答える
-1

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

列挙型:

enum Status { Success, Fail, Pending }

ジェネリック クラス:

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

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));
于 2020-01-21T19:27:13.793 に答える
-2

あなたの問題を解決するための最良の(そして最も簡単な)方法は、列挙型の拡張メソッドを書くことだと思います:

public static string GetUserFriendlyString(this PublishStatusses status)
    {

    }
于 2016-10-31T18:26:34.103 に答える
-3

完全にカスタマイズ可能なものが必要な場合は、ここで私のソリューションを試してください。

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

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

于 2009-01-26T11:01:17.493 に答える