在编程中,枚举(Enum)是一种常用的数据类型,它允许为一组相关的常量定义一个名称。枚举的名称通常简洁明了,但有时对于最终用户来说,这些名称可能不够描述性。因此,希望为枚举字段关联更长、更易于理解的描述,通常用于用户界面(UI)。例如,一个下拉框(ComboBox)的值可能来自枚举字段,而其文本可能来自该字段的描述。
为了实现这一目标,可以使用描述性属性(Description Attribute)来装饰枚举字段,以提供更详细的描述。然而,获取这些属性提供的描述需要使用反射(Reflection),这是应该尽量避免的操作。本文介绍的类允许一次性创建枚举类型的描述字典,以便在需要时随时使用。
这个类继承自Dictionary
以下是类的定义和实现:
public class EnumDescriptionDictionary : Dictionary
where TEnum : struct, IComparable, IConvertible, IFormattable
{
public EnumDescriptionDictionary()
{
if (!typeof(TEnum).IsEnum)
{
throw new NotSupportedException("Generic parameter T must be of type Enum.");
}
var fields = typeof(TEnum).GetFields(BindingFlags.Public | BindingFlags.Static);
foreach (var field in fields)
{
var descAtt = field.GetCustomAttribute();
if (descAtt != null)
{
var desc = descAtt.Description;
if (!string.IsNullOrEmpty(desc))
{
Add((TEnum)Enum.Parse(typeof(TEnum), field.Name), desc);
continue;
}
}
Add((TEnum)Enum.Parse(typeof(TEnum), field.Name), field.Name);
}
}
public new void Remove(TEnum key)
{
throw new InvalidOperationException(string.Format("Items may not be removed from this dictionary as type '{0}' has not changed.", typeof(TEnum).Name));
}
}
这个类首先检查泛型参数T是否为枚举类型。如果不是,它将抛出一个NotSupportedException异常。然后,它使用BindingFlags来获取枚举类型的所有公共静态字段,并遍历这些字段。对于每个字段,它尝试获取描述性属性(DescriptionAttribute)。如果找到了,并且属性的描述不为空,则将该描述添加到字典中。如果没有找到描述性属性,或者属性的描述为空,则使用字段的名称作为描述。
以下是一个测试枚举和使用EnumDescriptionDictionary的示例程序:
internal enum TestEnum
{
[Description("Not Operational")]
Nop,
Installation,
[Description("System Set-up")]
SystemSetup,
[Description("Import / Export")]
ImportExport,
Configuration,
[Description("Help and Documentation")]
Help,
Uninstall
}
class Program
{
static void Main(string[] args)
{
var dict = new EnumDescriptionDictionary();
Console.WriteLine();
Console.WriteLine("Value: {0}\tDesc: '{1}'", TestEnum.Nop, dict[TestEnum.Nop]);
Console.WriteLine("Value: {0}\tDesc: '{1}'", TestEnum.Configuration, dict[TestEnum.Configuration]);
Console.WriteLine();
Console.WriteLine("Press Enter to exit.");
Console.ReadLine();
}
}
这个程序将输出以下内容:
Value: Nop Desc: 'Not Operational'
Value: Configuration Desc: 'Configuration'
.NET没有提供原生的约束来指定泛型参数必须是枚举类型。但是,可以使用Jon Skeet的unconstrained-melody库来实现这一点。这个库提供了许多枚举实用工具,这些工具可以替代上面所做的工作。
The JIT compiler needs a definition of a value type that describes its layout when it gets boxed. Most of them are baked into mscorlib, like System.Int32. The enum keyword lets you create a new value type. The compiler must thus provide a definition for it in the metadata. Which is what you are looking at. You'll see static fields for each enumeration member, used by ToString(). And one instance field name value__ that stores the enumeration value. Key point is that this only exists in the boxed version of an enum value.