【问题标题】:Enum ToString with user friendly strings带有用户友好字符串的枚举 ToString
【发布时间】:2010-10-03 12:36:39
【问题描述】:

我的枚举包含以下值:

private enum PublishStatusses{
    NotCompleted,
    Completed,
    Error
};

不过,我希望能够以用户友好的方式输出这些值。
我不需要能够再次从字符串变为值。

【问题讨论】:

标签: c# enums tostring


【解决方案1】:

我使用 System.ComponentModel 命名空间中的Description 属性。简单地装饰枚举:

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

【讨论】:

  • 这个例子更容易阅读。 stackoverflow.com/questions/1415140/…
  • 我怀疑使用此解决方案中所述的反射会显着降低性能。 Will 使用 ToFriendlyString 扩展方法的代码更容易理解,性能也应该非常快。
  • 我喜欢@RayL 链接的版本,因为它只会将扩展方法添加到 Enums。如果这就是您想要使用它的全部内容(如 ArgumentException 所示,那么没有理由让该方法完全通用。
  • 这确实意味着每个枚举都需要它自己的扩展方法。这是更一般的用途,确实需要更多的工作,但您可能希望在我们决定性能之前量化“快速”的含义。
  • @petar 有效,但如果您希望向用户显示友好的字符串,则无效。 MY_TYPE 将带有下划线且不可自定义。
【解决方案2】:

我使用扩展方法来做到这一点:

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

【讨论】:

  • 这比属性答案要干净得多。不错!
  • @pennyrave:嗯。许多 UI 组件都希望找到并使用 DisplayNameAttribute 和 DescriptionAttribute。事实上,现在,我使用这些和扩展方法来轻松获取这些值。
  • 我看到的问题是你一直在编写这些扩展方法。使用属性机制,这是一种简单的装饰方式,并且只调用一个方法。
  • 不确定您的意思?
  • 在我看来,最好允许default case 实现返回me.ToString(),并且只为要覆盖的枚举值提供 switch case 语句。在您的示例中,我知道它们都是不同的,但在实际用例中,我怀疑大多数单字枚举值就足够了,您只会为多字枚举值提供覆盖。
【解决方案3】:

也许我遗漏了什么,但 Enum.GetName 有什么问题?

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

编辑:对于用户友好的字符串,您需要通过 .resource 来完成国际化/本地化,并且可以说使用基于枚举键的固定键比使用装饰器属性更好。

【讨论】:

  • 我返回枚举的字面值,而不是一些用户友好的值。
  • oic - 有一个相当大的情况是你必须根据这个值通过一个字符串资源库,因为替代(装饰器属性)不支持 I18N
  • 在 I18N 的情况下,我会让 GetDescription() 方法在资源库中搜索翻译后的字符串,然后回退到描述,然后回退到文字。
  • +1 用于 MyEnum.ToString() 作为本地化的资源键。多年来我一直这样做
  • @annakata 我们实际上已经扩展了属性机制以包括对 l18N 的支持,实际上这是一个简单的更改。
【解决方案4】:

我创建了一个反向扩展方法将描述转换回枚举值:

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

【讨论】:

  • 很抱歉,感谢您提供帮助!虽然因为这是一个问答网站,但回答应该是尝试直接回答问题。并且问题特别指出“我不需要能够再次从字符串转到值。”再次感谢!
  • 感谢您的积极批评。成为一个网站的新手并了解它的文化和细微差别总是很困难的。我很高兴有像你这样的人直面新人。再次感谢您没有抛弃新人。
  • @Jesse 4 年后,有人很高兴在这里找到 bjrichardson 代码! SO 可能是一个问答网站,但这并不意味着问题在被回答后就死了。
【解决方案5】:

这里最简单的解决方案是使用自定义扩展方法(至少在 .NET 3.5 中 - 您可以将其转换为早期框架版本的静态辅助方法)。

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

我在这里假设您想要返回的不是枚举值的实际名称(您可以通过简单地调用 ToString 来获得)。

【讨论】:

  • 虽然有效,但我更喜欢属性方式。这样我就可以将我的 toSTring 方法放在一个单独的库中,同时将自定义字符串表示与枚举本身放在一起
  • 很公平。我想这种方法的一个优点是您可以在指定某个状态变量的方法中包含一个参数,然后根据此更改返回的字符串表示形式。
  • 是的,这完全取决于我猜的方法的范围。虽然 Attribute 方式更通用,但您的解决方案更本地化.. 最终都是关于需求。
  • 您可以将扩展方法放在任何您想要的地方。您只需在要使用它们的地方引用它。
  • 是的,但这意味着每次你引入一个你想要一个友好名称的新枚举时都应该重写这个扩展方法。这也意味着您的所有应用程序都将携带所有其他应用程序的友好名称......
【解决方案6】:

另一篇文章是 Java。在 C# 中,您不能将方法放在 Enums 中。

只需这样做:

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

如果你想为你的枚举值使用不同的显示值,你可以使用属性和反射。

【讨论】:

  • toString 在所有情况下都不安全 - 具有多个具有相同值的条目的枚举(例如整数枚举)将返回第一个匹配值的键,而不是测试项目的键,这这就是首选 Enum.GetName 的原因
  • 嗯,对于他的特定枚举来说,这是最简单的解决方案
【解决方案7】:

其他一些避免类/引用类型的更原始的选项:

  • 数组方法
  • 嵌套结构方法

数组法

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 数组),因为名称字符串最好来自资源(即配置文件或数据库)而不是被硬编码,并且因为我最终将扩展方法放在 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 那里。但它失去了枚举本身的特性。因此,虽然 IMO 这是一个不错的选择,但它不能回答实际问题并得到 -1。 Net 0。抱歉,我们没有办法在 SO 中更好地记录它。
  • @TonyG 够公平的。在错过了关于 pluarlsight.com 的 .net 技能评估的几个问题后,我开始意识到 C# 枚举的深度,因此在决定应用哪种方法之前至少了解它们的能力可能是个好主意(尤其是对于普遍使用、重构可能需要一点时间;)。
【解决方案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());

【讨论】:

  • 这是一个谜,为什么这个评论不是被接受的,或者最被赞成的——没有反思,没有不必要的属性,非常适合枚举已经很好命名的简单情况。您可以更进一步地回答这个问题,并允许在返回“我的枚举”之前在大写字母之间添加空格。
  • 如果枚举已经很好地命名,则不需要任何扩展方法。只需使用现有的 ToString() 方法。 string result = "Result: " + ee;
  • 这应该是最好的答案。它适用于任何枚举。您甚至可以使用特定的 Enum 来实现它,只需将参数的 Enum 类型更改为使用它的实际 Enum。
  • 这个答案和所有 cmets 都忽略了对扩展描述的原始请求。你们完全错过了返回默认 ToString 值以外的其他内容的练习。我不会在这里对这个答案的所有注释投反对票,但我肯定愿意。
【解决方案9】:

您可以使用Humanizer 包和Humanize Enums 可能性。一个例子:

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)

【讨论】:

【解决方案10】:
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;
}

【讨论】:

  • 写一些文字解释为什么这应该起作用以及为什么 OP 不起作用总是很好。
  • 仅供参考,C# 代码约定需要具有小写首字母的局部变量和方法参数。一个例外是扩展方法中的this 参数,您可以在网络的许多示例中看​​到称为This。像你一样调用它的类型 (Enum Enum) 会降低代码的可读性。
【解决方案11】:

关于Ray Booysen,代码中有一个bug:Enum ToString with user friendly strings

您需要考虑枚举值的多个属性。

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

【讨论】:

  • 故意省略对多个描述属性的检查。如果枚举有两个,并且您使用 to 来生成描述,我想这是一个例外情况。我认为实际的错误是我没有执行 Single() 来引发异常。否则整个方法签名毫无意义。获取描述()?哪个描述?聚合?
【解决方案12】:

使用静态类代替枚举。

替换

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"

使用顶级“扩展方法”解决的问题:

私有枚举通常在另一个类中使用。扩展方法解决方案在那里无效,因为它必须在它自己的类中。此解决方案可以是私有的并嵌入到另一个类中。

【讨论】:

  • 这将在传递给方法时丢失Enums 的值,因为所有方法签名都需要string,因此可以传递任何内容;引入了额外验证的需求并降低了一般可读性。
【解决方案13】:

上述建议的干净摘要与示例:

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

【讨论】:

  • C#中有一个[Description("")]属性,为什么不用这个呢?
  • 当然使用 [Description("")] 是一种方法。但我希望样本完整。
【解决方案14】:

根据本文档: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

【讨论】:

【解决方案15】:

我碰巧是 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

基本内容:一个名为 EnumType 的枚举,具有三个值 V1、V2 和 V3。 “魔法”发生在 Sub Main() 中的 Console.WriteLine 调用中,其中最后一个参数只是 v.Description。这将为 V1 返回“一”,为 V2 返回“V2”,为 V3 返回“三”。这个 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# 在扩展等新主题上生锈了)

【讨论】:

    【解决方案16】:

    更简洁的总结:

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

    与下划线描述的用法相同。

    【讨论】:

      【解决方案17】:

      使用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
      

      【讨论】:

      • 如果你想要一个不同的枚举名称怎么办,例如有空格的东西。
      • 嗨@StealthRabbi,我认为这个帖子的另一个回复已经回答了这个问题 --> stackoverflow.com/a/479417/1107715
      【解决方案18】:

      如果你只想在单词之间添加一个空格,那么简单

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

      【讨论】:

        【解决方案19】:

        这是对 Ray Booysen 代码的更新,它使用通用的 GetCustomAttributes 方法和 LINQ 使事情变得更整洁。

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

        【讨论】:

        • 没明白为什么你需要它是通用的?如果你打算使用反射?
        • @LeeLouviere 主要是为了避免将struct(值类型)作为参数传递时的装箱。
        • 代替 numerationValue.GetType() 使用:typeof(T)。
        • 在没有 (YMMV) 可读性的情况下,对已接受的答案进行了巨大的单行改进。是的,使用 typeof(T)。
        【解决方案20】:

        我迟到了 7 年 :-) 但我确信这个话题经常被访问。
        所以我想在咖啡里加一点糖:

        “F”格式字符串说明符呢?

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

        不需要任何显式的函数调用。

        事实上,甚至不需要任何格式说明符。 如果将变量分配给字符串,ToString() 会起作用:

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

        如果要在 CamelCase 字符串的单词之间插入空格,则可以使用正则表达式:

        Regex.Replace(foo, "(\\B[A-Z])", " $1")
        

        【讨论】:

          【解决方案21】:

          对于标志枚举,包括。

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

          【讨论】:

            【解决方案22】:

            我使用一个泛型类来存储枚举/描述对和一个嵌套的帮助类来获取描述。

            枚举

            enum Status { Success, Fail, Pending }
            

            泛型类:

            注意:由于泛型类不能受 enum 约束,我改为使用 struct 约束并检查 enum 在构造函数中。

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

            【讨论】:

              【解决方案23】:

              我认为解决您的问题的最佳(也是最简单)的方法是为您的枚举编写一个扩展方法:

              public static string GetUserFriendlyString(this PublishStatusses status)
                  {
              
                  }
              

              【讨论】:

              • 有人早在 7 年前就说过了
              【解决方案24】:

              如果您想要完全可定制的东西,请在此处试用我的解决方案:

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

              基本上,这篇文章概述了如何将描述属性附加到每个枚举,并提供了一种从枚举映射到描述的通用方法。

              【讨论】:

              • 现在网站已关闭。
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2010-09-19
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多