.NET Enum The Next Level

本文介绍如何利用.NET中的反射和属性,使枚举成员关联到更多数据类型,如字符串描述及数值范围,从而增强枚举的功能性和灵活性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


声明:
本文内容出自:http://www.codeproject.com/useritems/DotNetEnumsNextLevel.asp
由于本人E文菜得实在离谱,对文章的“翻译”①仅限于自娱自乐,文中用词过于牵强而且漏洞百出,强烈建议读者打开上面的链接阅读原文

-------------------------------------------------------------

导言

      在这篇文章里我将对.NET中的枚举做进一步探索,本文不会含盖枚举的基本概念、语法或者使用方法(这些你可以通过MSDN得到详细的信息),最大的限制是枚举只能使用 Integer 数据类型。枚举提供了 ToString() 方法的支持,但却有限制(我会在文章后面详细论述)。主要地,我希望能够把我所列举的枚举元素不仅仅关联到整数数据,我将通过反射(Reflection)和属性(Attributes)跟使用尽量简单的例子来说明如何达到这一目标。

在 Enum 中使用 ToString()

我们先来创建一个简单的枚举。。。

None.gif public   enum  EmployeeType
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    RegularEmployee,
InBlock.gif    StoreManager,
InBlock.gif    ChainStoreManager,
InBlock.gif    DepartmentManager,
InBlock.gif    Supervisor
ExpandedBlockEnd.gif}

我们可以通过 ToString() 方法简单地获取到下列信息

None.gif EmployeeType employee  =  EmployeeType.ChainStoreManager;
None.gifConsole.WriteLine(employee.ToString());
None.gifConsole.WriteLine(EmployeeType.ChainStoreManager.ToString());
None.gif
ExpandedBlockStart.gifContractedBlock.gif
/**/ /*
InBlock.gif 输出结果: 
InBlock.gif
InBlock.gif ChainStoreManager 
InBlock.gif ChainStoreManager 
ExpandedBlockEnd.gif
*/

但我们如何才能获取到的结果类似“Chain Store Manager”包括空格呢?我们不能去创建一个包含空格的枚举成员,否则你的代码将不能编译通过,事实上我们有很多方案可以解决这个问题。

1、在枚举成员和字符串之间创建一个映射(可以使用数组或哈希表)
2、将枚举成员 ToString() 的结果作为为键指定到资源文件
3、使用反射。。。。(我将在下面讲到)

在枚举中使用属性

我将使用属性来达到一个字符串关联到枚举成员的目的,下面通过一个简单的例子来说明这是如何做到的。

None.gif public   class  EnumDescriptionAttribute : Attribute
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
private string m_strDescription;
InBlock.gif    
public EnumDescriptionAttribute(string strPrinterName)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        m_strDescription 
= strPrinterName;
ExpandedSubBlockEnd.gif    }

InBlock.gif
InBlock.gif    
public string Description
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif        
get dot.gifreturn m_strDescription; }
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

EnumDescriptionAttribute 类继承自 Attribute,它包含一个类型为String的属性Description,下面将该属性关联到枚举 EmployeeType 的所有成员上。

None.gif public   enum  EmployeeType
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    [EnumDescription(
"Regular Employee")]
InBlock.gif    RegularEmploye,
InBlock.gif    [EnumDescription(
"Store Manager")]
InBlock.gif    StoreManager,
InBlock.gif    [EnumDescription(
"Chain Store Manager")]
InBlock.gif    ChainStoreManager,
InBlock.gif    [EnumDescription(
"Department Manager")]
InBlock.gif    DepartmentManager,
InBlock.gif    [EnumDescription(
"On Floor Supervisor")]
InBlock.gif    Supervisor
ExpandedBlockEnd.gif}


从枚举获取到属性的值


为了获取到属性的值,我必须使用到反射,下是是一个简单的例子:

None.gif //  setup the enum
None.gif
EmployeeType employee  =  EmployeeType.ChainStoreManager;
None.gif
None.gif
//  get the field informaiton
None.gif
FieldInfo fieldInfo  =  employee.GetType().GetField( " ChainStoreManager " );
None.gif
None.gif
//  get the attributes for the enum field
None.gif
object [] attribArray  =  fieldInfo.GetCustomAttributes( false );
None.gif
None.gif
//  cast the one and only attribute to EnumDescriptionAttribute
None.gif
EnumDescriptionAttribute attrib  =  (EnumDescriptionAttribute)attribArray[ 0 ];
None.gif
None.gif
//  write the description
None.gif
console.WriteLine( " Description: {0} " , attrib.Description);
None.gif
ExpandedBlockStart.gifContractedBlock.gif
/**/ /*
InBlock.gif 输入结果: 
InBlock.gif Chain Store Manager
ExpandedBlockEnd.gif
*/
 

其中最重点的一行代码:FieldInfo fieldInfo = employee.GetType().GetField("ChainStoreManager"); 我们注意硬编码到里面的枚举成员名称ChainStoreManager实际上可以通过 ToString() 方法来代替。

一个获取描述信息的通用方法

其中使用了 ToString() 方法

None.gif public   static   string  GetEnumDescription(Enum enumObj)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    System.Reflection.FieldInfo fieldInfo 
= enumObj.GetType().GetField(enumObj.ToString());
InBlock.gif
InBlock.gif    
object[] attribArray = fieldInfo.GetCustomAttributes(false);
InBlock.gif    
if (attribArray.Length == 0)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
return String.Empty;
ExpandedSubBlockEnd.gif    }

InBlock.gif    
else
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        EnumDescriptionAttribute attrib 
= attribArray[0as EnumDescriptionAttribute;
InBlock.gif
InBlock.gif        
return attrib.Description;
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}


让枚举成员关联到更多的数据类型


到目前为止我们仅仅在我们的枚举成员中添加了描述信息,不过我们是完全可以让我们的枚举关联到任何一种数据类型的,我交将创建一个新的枚举来展示我的想法(这跟前面的做法一样)。

None.gif public   enum  ManagerType
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    StoreManager,
InBlock.gif    ChainManager,
InBlock.gif    Superivor
ExpandedBlockEnd.gif}

而且我还得创建一个 EnumDescription 的派生类 ManagerAttribute,跟提供两个价格信息(最高和最低薪水值)

None.gif public   class  ManagerAttribute : EnumDescriptionAttribute
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
private int m_intMinSalary;
InBlock.gif    
private int m_intMaxSalary;
InBlock.gif    
public ManagerAttribute(string strDescription, int intMinSalary, int intMaxSalary)
InBlock.gif        : 
base(strDescription)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        m_intMinSalary 
= intMinSalary;
InBlock.gif        m_intMaxSalary 
= intMaxSalary;
ExpandedSubBlockEnd.gif    }

InBlock.gif
InBlock.gif    
public ManagerAttribute(string strDescription)
InBlock.gif        : 
base(strDescription)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
ExpandedSubBlockEnd.gif    }

InBlock.gif
InBlock.gif    
public int MinSalary
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif        
get dot.gifreturn m_intMinSalary; }
ExpandedSubBlockStart.gifContractedSubBlock.gif        
set dot.gif{ m_intMinSalary = value; }
ExpandedSubBlockEnd.gif    }

InBlock.gif    
public int MaxSalary
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif        
get dot.gifreturn m_intMaxSalary; }
ExpandedSubBlockStart.gifContractedSubBlock.gif        
set dot.gif{ m_intMaxSalary = value; }
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

现在我将 ManagerAttribute 关联到所有枚举成员上,为了让代码的可读性更强,给 ManagerAttributes 的所有属性都附了值。

None.gif public   enum  ManagerType
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    [Manager(
"Store Manager", MinSalary=40000, MaxSalary=100000)]
InBlock.gif    StoreManager,
InBlock.gif    [Manager(
"Chain Manager", MinSalary=50000, MaxSalary=110000)]
InBlock.gif    ChainManager,
InBlock.gif    [Manager(
"Store Supervisor", MinSalary=30000, MaxSalary=50000)]
InBlock.gif    Superivor
ExpandedBlockEnd.gif}

下一步是改进获取 EnumDescriptionAttribute 属性值的通用方法,让它支持所有数据类型,使用C# 2.0 中的泛型(Generics)很容易办到

None.gif public   static  T GetAttribute < T > (Enum enumObj) where T : EnumDescriptionAttribute
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
// get field informaiton for our enum element
InBlock.gif
    FieldInfo fieldInfo = enumObj.GetType().GetField(enumObj.ToString());
InBlock.gif
InBlock.gif    
// get all the attributes associated with our enum
InBlock.gif
    object[] attribArray = fieldInfo.GetCustomAttributes(false);
InBlock.gif
InBlock.gif    
if (attribArray.Length == 0)
InBlock.gif        
return default(T);
InBlock.gif    
else
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
// cast the attribute and return it
InBlock.gif
        T attrib = (T)attribArray[0];
InBlock.gif        
if (attrib != null)
InBlock.gif            
return attrib;
InBlock.gif        
else
InBlock.gif            
return default(T);
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}


工具方法

到目前为止我们已经写了两个工具类,一个是简单地实现了从枚举中获取描述信息,另一个继承自 EnumDescriptionAttribute 的更通用的方法可以获取任何数据类型的属性值,你可以把它们添加到你的枚举工具类(如:EnumHelper)中去,这里我还是简单地把它放在 EnumDescriptionAttribute 中。

None.gif public   class  EnumDescriptionAttribute  : Attribute
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
private string m_strDescription;
InBlock.gif    
public EnumDescriptionAttribute(string strEnumDescription)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        m_strDescription 
= strEnumDescription;
ExpandedSubBlockEnd.gif    }

InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif    
public string Description dot.gifget dot.gifreturn m_strDescription; } }
InBlock.gif
InBlock.gif    
public static string GetEnumDescription(Enum enumObj)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        System.Reflection.FieldInfo fieldInfo 
= enumObj.GetType().GetField(enumObj.ToString());
InBlock.gif        
object[] attribArray = fieldInfo.GetCustomAttributes(false);
InBlock.gif        
if (attribArray.Length == 0)
InBlock.gif            
return String.Empty;
InBlock.gif        
else
ExpandedSubBlockStart.gif
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值