工作上常遇到的需求:

旗標性質欄位在資料庫被定義成CHAR(1),用單一字元代表不同意義,例如:  1=新增、2=修改、3=刪除、A=同意、R=同意、W=撤回、C=取消。針對這類旗標,UI常會使用下拉選單或Radio Button列出選項讓使用者選取;而在顯示時需將資料庫讀到的"A"轉成"同意"方便理解。

實作時,我偏好在ViewModel將這種欄位屬性定義成.NET列舉(Enum)型別,UI上直接用列舉項目當作下拉選單選項,利用每個列舉項目都有對應int值的特性,直接將各項目對應成要存入的字元,例如:

    public enum MyEnum
    {
        新增 = 1,
        修改 = 2,
        刪除 = 3,
        同意 = (int)'A',
        否決 = (int)'R',
        撤回 = (int)'W',
        取消 = (int)'C'
    }

如此便能很方便地在列舉型別與CHAR(1)字元間互轉--如果有一個好用的工具函數的話!

以下就是我心中好用的工具函數:

        //參考: http://bit.ly/16yoItk
        /// <summary>
        /// 將列舉值轉為列舉型別
        /// </summary>
        /// <typeparam name="T">列舉型別</typeparam>
        /// <param name="value">列舉值字串</param>
        /// <returns></returns>
        public static T GetEnum<T>(string value) where T : struct, IConvertible
        {
            if (!typeof(T).IsEnum) 
                throw new ArgumentException("T must be an enumerated type");
            int n;
            //若非數字時且為單一字母,將其轉為CHAR
            if (!int.TryParse(value, out n) && value.Length == 1)
                value = ((int)value[0]).ToString();
            return ((T)Enum.Parse(typeof(T), value));
        }
        /// <summary>
        /// 將列舉型別轉為列舉值,可為數字或字元(ex: 1='1',65='A')
        /// </summary>
        /// <typeparam name="T">列舉型別</typeparam>
        /// <typeparam name="R">傳回型別,限int, char或string</typeparam>
        /// <param name="enumVal">列舉參數</param>
        /// <returns></returns>
        public static R GetEnumValue<T, R>(T enumVal) where T : struct, IConvertible
        {
            if (!typeof(T).IsEnum) 
                throw new ArgumentException("T must be an enumerated type");
            Type resType = typeof(R);
            if (resType != typeof(int) && resType != typeof(char) 
                && resType != typeof(string))
                throw new ArgumentException("R must be int, char or string");
            int n = enumVal.ToInt32(null);
            //R is int時,直接傳回數字
            if (resType == typeof(int))
                return (R)Convert.ChangeType(n, resType);
            //否則轉為Char後傳回(小於10則直接傳數字字元)
            char c = n < 10 ? n.ToString()[0] : (char)n;
            return (R)Convert.ChangeType(c, resType);
        }

實地測試:

    protected void Page_Load(object sender, EventArgs e)
    {
        foreach (MyEnum me in Enum.GetValues(typeof(MyEnum)))
        {
            //針對每個列舉項目取得int及string
            Response.Write(string.Format("<li>{0} / {1} / {2}",
                me, Common.GetEnumValue<MyEnum, int>(me),
                Common.GetEnumValue<MyEnum, string>(me)));
        }
        foreach (char c in "123ARWC")
        {
            //將單一字元轉為列舉
            Response.Write(string.Format("<li>{0} -&gt; {1}",
                c, Common.GetEnum<MyEnum>(c.ToString())));
        }
        Response.End();
    }

測試成功!!

新增 / 1 / 1 
修改 / 2 / 2 
刪除 / 3 / 3 
同意 / 65 / A 
取消 / 67 / C 
否決 / 82 / R 
撤回 / 87 / W 
1 -> 新增 
2 -> 修改 
3 -> 刪除 
A -> 同意 
R -> 否決 
W -> 撤回 
C -> 取消

Comments

# by 小黑

滿屌的~

# by Davidson

最近剛好有遇,感謝好方法。 我只有想到懶人方法 Orz.... 從 SQL 下手 ~_~ public enum MyEnum { 新增 = '1', 修改 = '2', 刪除 = '3', 同意 = 'A', 否決 = 'R', 撤回 = 'W', 取消 = 'C' } INSERT 的時候將該欄位值利用 SQL語法 CHAR(@InsValue) QUERY 的時候透過 ASCII(FieldName) as [FieldName] 來取得 透過這樣的畸形方式,就可結合 Dapper 自動轉換了,但是就是 查詢語法不漂亮 XDD 分享參考 ^^

# by Jeffrey

to Davidson, 這解法有創意,感謝分享。

Post a comment