[Abstract] Here is a sample to store text descriptions of enum fields to DescriptionAttribute, and convert them to a enum field name to description dictionary.  So we can use it as the data source of dropdownlist or listbox easily.

開發系統時,常會用到下拉選單選項文字與值不同的設計。一般而言,文字要明確完整方便User閱讀,而各文字對應值常需配合資料庫欄位寬度,寫入資料庫時得轉成兩、三碼固定長度的特定代碼。

如下例,資料庫欄位為VARCHAR(2),四個選項各有其對應的兩碼代碼。

要處理上述選項文字與值不同的狀況,使用config檔、資料檔或資料庫保存對應表是一種解決方式,另一種做法是將它宣告成enum,如此在Visual Studio中可以享受Intellisense提示,甚至可用Code Snippet自動產生所有switch..case,最重要的,若打錯字也可在編譯期間被發現。

在之前討論enum, string, int轉換的文章裡,網友大估分享了用[Description("...")]保存列舉描述的做法,不失為一個簡潔的對應文字保存方式,例如:

public enum ViewEngineType
{
    [Description("Razor")]
    RZ,
    [Description("Webform(ASCX)")]
    WF,
    [Description("Spark")]
    SP,
    [Description("NHaml")]
    NH
}

最近遇到類似需求,決定一不做二不休,寫了一個小函數將以上的列舉宣告直接轉成DropDownList可用的資料來源。廢話不多說,直接看Code:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
 
public partial class EnumDropdown_Default : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            DropDownList1.DataSource =
                EnumListHelper.GetEnumDescDictionary(typeof(ViewEngineType));
            DropDownList1.DataTextField = "value";
            DropDownList1.DataValueField = "key";
            DropDownList1.DataBind();
        }
    }
}
 
public enum ViewEngineType
{
    [Description("Razor")]
    RZ,
    [Description("Webform(ASCX)")]
    WF,
    [Description("Spark")]
    SP,
    [Description("NHaml")]
    NH
}
 
public static class EnumListHelper
{
    //enum在執行階段是不會變動的,故使用Cache避免反覆執行
    static Dictionary<Type, Dictionary<string, string>> _cache
        = new Dictionary<Type, Dictionary<string, string>>();
 
    //將enum的列舉文字及[Description("..")]轉成Dictionary<string, string>
    public static Dictionary<string, string> GetEnumDescDictionary(Type enumType)
    {
        if (_cache.ContainsKey(enumType))
            return _cache[enumType];
        Dictionary<string, string> dict = new Dictionary<string, string>();
        foreach (string name in Enum.GetNames(enumType))
        {
            FieldInfo fi = enumType.GetField(name);
            DescriptionAttribute[] attrs =
                (DescriptionAttribute[])fi.GetCustomAttributes(
                    typeof(DescriptionAttribute), false);
            dict.Add(name, attrs.Length > 0 ? attrs[0].Description : name);
        }
        _cache.Add(enumType, dict);
        return dict;
    }
}

Comments

# by 大估

關於Enum+DescriptionAttribute,在.net3.5還有另一種寫法,提供給大家作參考… http://www.codeproject.com/KB/cs/enumdatabinding.aspx?select=2217063

# by 小黑

請問黑大,因為一般大都是將資料鍵在資料庫,哪些狀況下可以考慮使用 enum 當作資料來源?

# by Jeffrey

to 小黑, 這問題倒沒有絕對答案。列舉項目清單保存在DB的好處是未來要新增項目時不需修改程式、且可以在Procedure端JOIN出相關代碼的對照中文,但缺點是會增加系統複雜度(要多寫讀取DB的部分、維護列舉項目的UI)、耗消一些效能(程式直接取值 vs 讀取DB取值,通常還需要加上Cache機制以防效能受拖累)。用或不用,要視各系統的相關條件而定。 由以上的優缺點來分析,當列舉項目預期數年都不會增刪,也沒有必要在純DB端取得對照,則用enum來做,不失為一種符合KISS法則的設計。

Post a comment