声明:
本文内容出自:
http://www.codeproject.com/useritems/DotNetEnumsNextLevel.asp
由于本人E文菜得实在离谱,对文章的“翻译”①仅限于自娱自乐,文中用词过于牵强而且漏洞百出,
强烈建议读者打开上面的链接 阅读原文 。
-------------------------------------------------------------
导言 在这篇文章里我将对.NET中的枚举做进一步探索,本文不会含盖枚举的基本概念、语法或者使用方法(这些你可以通过MSDN得到详细的信息),最大的限制是枚举只能使用 Integer 数据类型。枚举提供了 ToString() 方法的支持,但却有限制(我会在文章后面详细论述)。主要地,我希望能够把我所列举的枚举元素不仅仅关联到整数数据,我将通过反射(Reflection)和属性(Attributes)跟使用尽量简单的例子来说明如何达到这一目标。
在 Enum 中使用 ToString() 我们先来创建一个简单的枚举。。。
public
enum
EmployeeType
{ RegularEmployee, StoreManager, ChainStoreManager, DepartmentManager, Supervisor }
我们可以通过 ToString() 方法简单地获取到下列信息
EmployeeType employee
=
EmployeeType.ChainStoreManager; Console.WriteLine(employee.ToString()); Console.WriteLine(EmployeeType.ChainStoreManager.ToString());
/**/
/* 输出结果: ChainStoreManager ChainStoreManager */
但我们如何才能获取到的结果类似“Chain Store Manager”包括空格呢?我们不能去创建一个包含空格的枚举成员,否则你的代码将不能编译通过,事实上我们有很多方案可以解决这个问题。
1、在枚举成员和字符串之间创建一个映射(可以使用数组或哈希表) 2、将枚举成员 ToString() 的结果作为为键指定到资源文件 3、使用反射。。。。(我将在下面讲到)在枚举中使用属性 我将使用属性来达到一个字符串关联到枚举成员的目的,下面通过一个简单的例子来说明这是如何做到的。
public
class
EnumDescriptionAttribute : Attribute
{ private string m_strDescription; public EnumDescriptionAttribute( string strPrinterName) { m_strDescription = strPrinterName; } public string Description { get { return m_strDescription; } } }
EnumDescriptionAttribute 类继承自 Attribute,它包含一个类型为String的属性Description,下面将该属性关联到枚举 EmployeeType 的所有成员上。
public
enum
EmployeeType
{ [EnumDescription( " Regular Employee " )] RegularEmploye, [EnumDescription( " Store Manager " )] StoreManager, [EnumDescription( " Chain Store Manager " )] ChainStoreManager, [EnumDescription( " Department Manager " )] DepartmentManager, [EnumDescription( " On Floor Supervisor " )] Supervisor }
从枚举获取到属性的值 为了获取到属性的值,我必须使用到反射,下是是一个简单的例子:
//
setup the enum
EmployeeType employee
=
EmployeeType.ChainStoreManager;
//
get the field informaiton
FieldInfo fieldInfo
=
employee.GetType().GetField(
"
ChainStoreManager
"
);
//
get the attributes for the enum field
object
[] attribArray
=
fieldInfo.GetCustomAttributes(
false
);
//
cast the one and only attribute to EnumDescriptionAttribute
EnumDescriptionAttribute attrib
=
(EnumDescriptionAttribute)attribArray[
0
];
//
write the description
console.WriteLine(
"
Description: {0}
"
, attrib.Description);
/**/
/* 输入结果: Chain Store Manager*/
其中最重点的一行代码:FieldInfo fieldInfo = employee.GetType().GetField("ChainStoreManager"); 我们注意硬编码到里面的枚举成员名称ChainStoreManager实际上可以通过 ToString() 方法来代替。一个获取描述信息的通用方法 其中使用了 ToString() 方法
public
static
string
GetEnumDescription(Enum enumObj)
{ System.Reflection.FieldInfo fieldInfo = enumObj.GetType().GetField(enumObj.ToString()); object [] attribArray = fieldInfo.GetCustomAttributes( false ); if (attribArray.Length == 0 ) { return String.Empty; } else { EnumDescriptionAttribute attrib = attribArray[ 0 ] as EnumDescriptionAttribute; return attrib.Description; } }
让枚举成员关联到更多的数据类型 到目前为止我们仅仅在我们的枚举成员中添加了描述信息,不过我们是完全可以让我们的枚举关联到任何一种数据类型的,我交将创建一个新的枚举来展示我的想法(这跟前面的做法一样)。
public
enum
ManagerType
{ StoreManager, ChainManager, Superivor }
而且我还得创建一个 EnumDescription 的派生类 ManagerAttribute,跟提供两个价格信息(最高和最低薪水值)
public
class
ManagerAttribute : EnumDescriptionAttribute
{ private int m_intMinSalary; private int m_intMaxSalary; public ManagerAttribute( string strDescription, int intMinSalary, int intMaxSalary) : base (strDescription) { m_intMinSalary = intMinSalary; m_intMaxSalary = intMaxSalary; } public ManagerAttribute( string strDescription) : base (strDescription) { } public int MinSalary { get { return m_intMinSalary; } set { m_intMinSalary = value; } } public int MaxSalary { get { return m_intMaxSalary; } set { m_intMaxSalary = value; } } }
现在我将 ManagerAttribute 关联到所有枚举成员上,为了让代码的可读性更强,给 ManagerAttributes 的所有属性都附了值。
public
enum
ManagerType
{ [Manager( " Store Manager " , MinSalary = 40000 , MaxSalary = 100000 )] StoreManager, [Manager( " Chain Manager " , MinSalary = 50000 , MaxSalary = 110000 )] ChainManager, [Manager( " Store Supervisor " , MinSalary = 30000 , MaxSalary = 50000 )] Superivor }
下一步是改进获取 EnumDescriptionAttribute 属性值的通用方法,让它支持所有数据类型,使用C# 2.0 中的泛型(Generics)很容易办到
public
static
T GetAttribute
<
T
>
(Enum enumObj) where T : EnumDescriptionAttribute
{ // get field informaiton for our enum element FieldInfo fieldInfo = enumObj.GetType().GetField(enumObj.ToString()); // get all the attributes associated with our enum object [] attribArray = fieldInfo.GetCustomAttributes( false ); if (attribArray.Length == 0 ) return default (T); else { // cast the attribute and return it T attrib = (T)attribArray[ 0 ]; if (attrib != null ) return attrib; else return default (T); } }
工具方法 到目前为止我们已经写了两个工具类,一个是简单地实现了从枚举中获取描述信息,另一个继承自 EnumDescriptionAttribute 的更通用的方法可以获取任何数据类型的属性值,你可以把它们添加到你的枚举工具类(如:EnumHelper)中去,这里我还是简单地把它放在 EnumDescriptionAttribute 中。
public
class
EnumDescriptionAttribute : Attribute
{ private string m_strDescription; public EnumDescriptionAttribute( string strEnumDescription) { m_strDescription = strEnumDescription; } public string Description { get { return m_strDescription; } } public static string GetEnumDescription(Enum enumObj) { System.Reflection.FieldInfo fieldInfo = enumObj.GetType().GetField(enumObj.ToString()); object [] attribArray = fieldInfo.GetCustomAttributes( false ); if (attribArray.Length == 0 ) return String.Empty; else { EnumDescriptionAttribute attrib = attribArray[ 0 ] as EnumDescriptionAttribute; return attrib.Description; } } public static T GetAttribute < T > (Enum enumObj) where T : EnumDescriptionAttribute { System.Reflection.FieldInfo fieldInfo = enumObj.GetType().GetField(enumObj.ToString()); object [] attribArray = fieldInfo.GetCustomAttributes( false ); if (attribArray.Length == 0 ) return default (T); else { T attrib = (T)attribArray[ 0 ]; if (attrib != null ) return attrib; else return default (T); } } }
最后。。。 获取一条描述信息的代码如下:
string
desc
=
EnumDescriptionAttribute.GetEnumDescription(EmployeeType.DepartmentManager);
下面是获取 ManagerAttribute 属性的代码:
ManagerAttribute manager
=
EnumDescriptionAttribute.GetAttribute
<
ManagerAttribute
>
(EmployeeType.DepartmentManager); Console.WriteLine(
"
Manager: {0}, Min Salary: {1}, Max Salary {2}
"
, attrib.Description, manager.MinSalary, manager.MaxSalary);
注释: ①实际上谈不上翻译,只能说是将自己的理解写出来