c# - 如何为枚举提供用户友好的名称?

标签 c# .net localization enums naming-conventions

<分区>

我有一个像这样的枚举

Enum Complexity
{
  NotSoComplex,
  LittleComplex,
  Complex,
  VeryComplex
}

我想在下拉列表中使用它,但不想在列表中看到这样的 Camel 名称(对用户来说看起来很奇怪)。相反,我想用正常的措辞,比如 没那么复杂 小复杂(等)

另外,我的应用程序是多语言的,我希望能够显示这些本地化的字符串,我使用了一个助手 TranslationHelper(string strID),它为我提供了字符串 ID 的本地化版本。

我有一个可行的解决方案,但不是很优雅: 我为枚举创建了一个辅助类,其中一个成员 Complexity 和 ToString() 被覆盖,如下所示(代码简化)

public class ComplexityHelper
{
    public ComplexityHelper(Complexity c, string desc)
    { m_complex = c; m_desc=desc; }

    public Complexity Complexity { get { ... } set {...} }
    public override ToString() { return m_desc; }

    //Then a static field like this 

    private static List<Complexity> m_cxList = null;

    // and method that returns the status lists to bind to DataSource of lists
    public static List<ComplexityHelper> GetComplexities() 
    {
        if (m_cxList == null)
        {
           string[] list = TranslationHelper.GetTranslation("item_Complexities").Split(',');
           Array listVal = Enum.GetValues(typeof(Complexities));
           if (list.Length != listVal.Length)
               throw new Exception("Invalid Complexities translations (item_Complexities)");
           m_cxList = new List<Complexity>();
           for (int i = 0; i < list.Length; i++)
           {
             Complexity cx = (ComplexitylistVal.GetValue(i);
             ComplexityHelper ch = new ComplexityHelper(cx, list[i]);
             m_cxList.Add(ch);
           }
        }
        return m_cxList;
    }
}

虽然可行,但我对此并不满意,因为我必须为我需要在选择列表中使用的各种枚举进行类似的编码。

有没有人对更简单或更通用的解决方案有建议?

谢谢 博格丹

最佳答案

基本友好名称

使用 Description attribute: *

enum MyEnum
{
    [Description("This is black")]
    Black,
    [Description("This is white")]
    White
}

还有一个方便的枚举扩展方法:

public static string GetDescription(this Enum value)
{
    FieldInfo field = value.GetType().GetField(value.ToString());
    object[] attribs = field.GetCustomAttributes(typeof(DescriptionAttribute), true);
    if(attribs.Length > 0)
    {
        return ((DescriptionAttribute)attribs[0]).Description;
    }
    return string.Empty;
}

这样使用:

MyEnum val = MyEnum.Black;
Console.WriteLine(val.GetDescription()); //writes "This is black"

(注意这并不完全适用于位标志...)

本地化

.NET 中有一个完善的模式用于处理每个字符串值的多种语言 - 使用 resource file , 扩展方法从资源文件中读取:

public static string GetDescription(this Enum value)
{
    FieldInfo field = value.GetType().GetField(value.ToString());
    object[] attribs = field.GetCustomAttributes(typeof(DescriptionAttribute), true));
    if(attribs.Length > 0)
    {
        string message = ((DescriptionAttribute)attribs[0]).Description;
        return resourceMgr.GetString(message, CultureInfo.CurrentCulture);
    }
    return string.Empty;
}

任何时候我们都可以利用现有的 BCL 功能来实现我们想要的,这绝对是探索的第一条途径。这最大限度地降低了复杂性,并使用了许多其他开发人员已经熟悉的模式。

将它们放在一起

为了让它绑定(bind)到 DropDownList,我们可能想要跟踪控件中的真实枚举值,并将翻译后的友好名称限制为视觉糖。我们可以通过使用匿名类型和列表中的 DataField 属性来做到这一点:

<asp:DropDownList ID="myDDL"
                  DataTextField="Description"
                  DataValueField="Value" />

myDDL.DataSource = Enum.GetValues(typeof(MyEnum)).OfType<MyEnum>().Select(
    val => new { Description = val.GetDescription(), Value = val.ToString() });

myDDL.DataBind();

让我们分解该 DataSource 行:

  • 首先我们调用Enum.GetValues(typeof(MyEnum)) ,这让我们得到一个松散类型的 Array的值(value)观
  • 接下来我们调用OfType<MyEnum>()将数组转换为 IEnumerable<MyEnum>
  • 然后我们调用Select()并提供一个 lambda 来转换一个包含两个字段 Description 和 Value 的新对象。

DataTextField 和 DataValueField 属性在数据绑定(bind)时进行反射评估,因此它们将在 DataItem 上搜索具有匹配名称的字段。

-注意在主文中,作者自己写了DescriptionAttribute这是不必要的类,因为 .NET 的标准库中已经存在。-

关于c# - 如何为枚举提供用户友好的名称?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1331487/

相关文章:

c# - 如何实现业务伙伴提供的WSDL?

c# - Fluent API,Entity Framework Core 中的多对多

c# - P/Invoke 动态 DLL 搜索路径

qt - 如何更新 CMake Qt 项目中的 *.ts(用于 Qt Linguist)文件?

objective-c - Cocoa 中的本地化更新

c# - 我能否让 Entity Framework 使用具体类而不是接口(interface)(用于 Web 服务序列化)

c# - 大列表函数超时(C# 中的 LINQ 查询)

c# - 将 LINQ 与异步混合(从种子获取有效负载)

scala - Play Framework 2.2.0 - 使用过滤器和全局对象强制语言

c# - DrawImage 调整后的图像太小