.NET Enum The Next Level


聲明:
本文內容出自:http://www.codeproject.com/useritems/DotNetEnumsNextLevel.asp
由於本人E文菜得實在離譜,對文章的“翻譯”①僅限於自娛自樂,文中用詞過於牽強而且漏洞百出,強烈建議讀者打開上面的鏈接閱讀原文

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

導言

      在這篇文章裏我將對.NET中的枚舉做進一步探索,本文不會含蓋枚舉的基本概念、語法或者使用方法(這些你可以通過MSDN得到詳細的信息),最大的限制是枚舉只能使用 Integer 數據類型。枚舉提供了 ToString() 方法的支持,但卻有限制(我會在文章後面詳細論述)。主要地,我希望能夠把我所列舉的枚舉元素不僅僅關聯到整數數據,我將通過反射(Reflection)和屬性(Attributes)跟使用盡量簡單的例子來說明如何達到這一目標。

在 Enum 中使用 ToString()

我們先來創建一個簡單的枚舉。。。

None.gifpublic 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.gifEmployeeType 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.gifpublic 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.gifpublic 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.gifpublic 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.gifpublic enum ManagerType
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    StoreManager,
InBlock.gif    ChainManager,
InBlock.gif    Superivor
ExpandedBlockEnd.gif}

而且我還得創建一個 EnumDescription 的派生類 ManagerAttribute,跟提供兩個價格信息(最高和最低薪水值)

None.gifpublic 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.gifpublic 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.gifpublic 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.gifpublic 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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章