如何使用中文列舉(Enum)(續)?

在前一篇如何使用中文列舉(Enum)?, 介紹了如何取得列舉中文說明的方法, 但每當有新的列舉時都要再寫一次嗎?

當然不, 此篇將會研究如何抽成共用的方法.

我們都知道, 相同的程式碼要抽成共用的方法來呼叫, 維護上比較便利, 程式碼也比較簡潔.

但有些情況無法去判斷是否有共用的程式碼時該怎麼辦?

小魯這邊的做法是當相近或是相同的程式碼些第二次的時候, 就要有警覺性.

當第三次發生時就一定要寫成共用方法, 甚至大部分在第二次就抽成共用了.

 

取得Enum的中文描述的方法很明顯不會是僅限於某個Enum使用,

所以應該要抽成共用方法來使用.

在目前泛型正夯的時期, 小魯也不免俗的來試一下

修改後的泛型方法如下:

public static class EnumHelper
{
    public static string GetDescription<T>(string value)
    {
        Type type = typeof(T);
        var name = Enum.GetNames(type)
                        .Where(f => f.Equals(value, StringComparison.CurrentCultureIgnoreCase))
                        .Select(d => d)
                        .FirstOrDefault();

        //// 找無相對應的列舉
        if (name == null)
            return string.Empty;

        //// 利用反射找出相對應的欄位, 並取得欄位設定DescriptionAttribute的值
        var field = type.GetField(name);
        var customAttribute = field.GetCustomAttributes(typeof(DescriptionAttribute), false);

        //// 無設定Description Attribute, 回傳Enum欄位名稱
        if (customAttribute == null || customAttribute.Length == 0)
            return name;

        //// 回傳Description Attribute的設定
        return ((DescriptionAttribute)customAttribute[0]).Description;
    }
}

小魯寫一個EnumHelp的靜態類別, 將取得中文描述方法寫成一個靜態的泛型方法

外部在呼叫時再將列舉帶入T中

static void Main(string[] args)
{
    var bookType = EnumHelper.GetDescription<BookTypeEnum>(BookTypeEnum.ComicBook.ToString());
    var result = string.Format("BookTypeEnum Description: {0}", bookType);

    Console.Write(result);
    Console.Read();
}

如此一來, 就可達到共用的效果.

.

.

.

有些眼尖的網友一定會發現一個問題

路人甲: "疑~小魯你這寫法任一型別都可以帶入且編譯不會報錯"

小魯: "安啦~等測試的時候就知道你寫錯了, 到時候再改就好啦!!"

路人乙: "小魯你太不負責任了啦~(╯-_-)╯ ~╩╩ (怒翻桌)"

為了避免網友翻桌, 小魯只好再找解決方案

有些人這時候一定會想到替泛型T加上條件約束不就好了

當初我也是這麼想

但查詢的結果發現沒有對Enum的條件約束

甚至在MSDN 限制適用於列舉型別中有提到一句話

"列舉型別不能是泛型,除非是巢狀於泛型型別中,才能是泛型。換句話說,列舉型別不能有自己的型別參數。"

真是晴天霹靂~

(註: 如果有網友知道Enum的條件約束, 麻煩請不吝告知, 謝謝!!)

但是沒關係, 山不轉路轉

換個方式來解

這時候可以回歸到用物件的多型來處理

public static class EnumHelper
{
    public static string GetDescription(Enum value)
    {
        Type type = value.GetType();

        //// 利用反射找出相對應的欄位
        var field = type.GetField(value.ToString());
        //// 取得欄位設定DescriptionAttribute的值
        var customAttribute = field.GetCustomAttributes(typeof(DescriptionAttribute), false);

        //// 無設定Description Attribute, 回傳Enum欄位名稱
        if (customAttribute == null || customAttribute.Length == 0)
        {
            return value.ToString();
        }

        //// 回傳Description Attribute的設定
        return ((DescriptionAttribute)customAttribute[0]).Description;
    }
}

參數型別直接用Enum,

利用型別的逆變性, 來限定參數只能是列舉型別

static void Main(string[] args)
{
    var bookType = EnumHelper.GetDescription(BookTypeEnum.ComicBook);
    var result = string.Format("BookTypeEnum Description: {0}", bookType);

    Console.Write(result);
    Console.Read();
}

如此一來, 就可以僅限制列舉型別又可達到共用的方法

另外, 此方法還可改寫成擴充方法來處理, 呼叫時更為便利

擴充方法這裡就不另外贅述了, 有興趣的網友可以去google看看

網路上有很多文章

 

 

參考網站:
https://msdn.microsoft.com/zh-tw/library/6e3t9w21%28v=vs.90%29.aspx

: 此篇文章有觀念錯誤之處,歡迎各位大大不吝指教