摘要:Extension Method on Enumeration
http://zhxing.iteye.com/blog/621475
主要是動態形成一個提供方法的 final class, 然後原本 Enum 中的元素都被宣告成這個類別型態的 final static fields, 最後在靜態建構子中給予當初 Enum 中的初始值. 這種作法就跟C++路線的一樣, 只不過在 Java 中只需定義 Enum, 後面的都由編譯器幫你橋好, 真方便啊!
那 C# 和 VB 中的 Enum 的值就只能是整數類的型態, 如 Byte, Integer, Long, SByte, Short, UInteger, Ulong 和 UShort, 預設是 Integer. 因為 Enum 不像一般類別可以繼承擴充, 所以都採用 Aggregation Extension, 也就是用另一個類別去包覆 Enum, 所以使用到 Enum 的時機也不會太複雜就是了!
.NET framework 在 3.0 後新增了 Extension Method, 這整個使類別擴充更具彈性; 那麼就總共有三種擴充方式: Inheritance Extension, Aggregation Extension 和 Extension Method. 如果你不清楚擴充方法, 可以參考下列連結:
http://msdn.microsoft.com/zh-tw/library/bb384936(v=VS.100).aspx
雖然好用, 但 Extension Method 是以靜態的方式去擴充!! 不過在 Linq 中到處都可以看到 Lambda Expression 與 Extension Method, 科科...
這種靜態擴充對 Enum 來說剛好適用, 因為一般 Enum 除了自己本身的元素之外, 不太會有其他的物件資料, 只會有物件結構, 而靜態函式專注處理物件自身中既有資料狀態, 這也是 Linq 大量使用 Extension Method 的方式.
講了這麼多, 總得貼一些程式碼, 不然就會覺得寂寞和空虛, 下面貼了 Enum 很常用到的函式:
Imports System.Runtime.CompilerServices
Module CommonEnumExtension
<extension()>
Public Function Name(ByVal e As [Enum]) As String
Return [Enum].GetName(e.GetType(), e)
End Function
<extension()>
Public Function toIntValue(ByVal e As [Enum]) As Integer
Dim fi As FieldInfo = e.GetType().GetField(e.Name)
Return CType(fi.GetValue(Nothing), Integer)
End Function
End Module
其實取得 Enum Name 很簡單, 但人家就是想要程式碼看起來比較優雅嘛 =w=, 一般取得元素名稱可以使用 ToString 或 GetName, 因為 ToString 的意圖太空泛, 說不定哪一天它的輸出值被改成跟 Type.ToString 一樣就囧了.
另一個轉型成整數的擴充方法, 倒是比較複雜, 怎用起 Reflection 來了, 其實我也不想這麼麻煩 (茶). 一般 Integer Casting 使用 CType 就可以, 如下:
CType( EnumObj, Integer)
但上面這行中的 EnumObj 如果更換成引數中的 e 就不行, 因為 [Enum] 無法轉型成 Integer, 我囧了, 我試了 CInt, Integer.Parse 和 Integer.TryParse 都不行, 但我又想對所有 Enum 提供這個方法, 我就只有想到用反射囉! 有誰知道更好的方法, 請麻煩告訴我 <3
當加入上面這兩個擴充方法後, 我隨便宣告個 Enum 就可以使用了!
Public Enum Action As Integer
View = 1
Query
End Enum
Dim actName as String = Action.View.Name
Dim intValue as Integer = Action.Query.toIntValue
actName 的值會是 “View”, 而後 intValue 會是 2. (怎麼這麼好用, 被揍飛 ~).
這邊提醒一下, 在 Name 擴充方法中, GetName 的 e 實際值與 e.GetType 的型態有可能會對應不起來而得到 Nothing, 這在 Enum 轉型時非常容易發生.
最後還是展示一下 Aggregation Extension 的寫法, 這個大家應該都很熟了! 就把作用函式包裝在另一個類別中, 一般這個函式的範圍是靜態的, 而 Enum 要不要放進包裝類別和作用函式的參數是否為 [Enum] 型就視設計者的需求而變.
Public Class MyWorks
Enum Action
view
query
End Enum
Public Shared Function Name(ByVal act As Action) As String
Return [Enum].GetName(act.GetType(), act)
End Function
End Class
Public Sub test()
MyWorks.Name(MyWorks.Action.view)
End Sub
如果你想知道 Enum 混合類別資料狀態的擴充可以參考另一篇 Enumeration with Class State.