Enum是如何用的?


一、前言

對於枚舉Enum,大家都非常熟悉,但枚舉出現的場景非常多的時候,是不是可以抽象出一個通用的解決方式。代碼大家都會寫,但並不是所有人都喜歡寫重復的代碼,老是用Ctrl+C和Ctrl+V累不累啊?很多人和我一樣,非常不喜歡寫重復的代碼,代碼寫多了,BUG就多。對於常見的場景,大部分人都喜歡抽象出來,寫一套通用的,每個地方都可以用,而且不易出錯。當然,你喜歡Ctrl+C和Ctrl+V,本人也沒有辦法....

二、int值,string值轉換成Enum

如下,一個簡單枚舉:

    public enum ExchangeType
    {
        [EnumFieldAttribute("不限", true)] 
        All = 0,
        [EnumFieldAttribute("深圳證券交易所")]
        SZSE = 1
    }

對於以下輸入代碼:

            ExchangeType type = (ExchangeType)3;

            if (type == ExchangeType.All)
            {
                Console.WriteLine("ExchangeType.All.");
            }
            else if (type == ExchangeType.SZSE)
            {
                Console.WriteLine("ExchangeType.SZSE.");
            }
            else
            {
                Console.WriteLine("Non Exist!");
            }

對於強制轉換,大家猜猜看,會輸出什么....

對於結果,大家可以自己去測試下,有可能與你期望的值不一致!

同樣對於以下代碼:

ExchangeType type;
bool success = Enum.TryParse<ExchangeType>("3", out  type);

TryParse執行的返回結果success也是成功的(為true),但期望值也不一定正確。

因此,對於枚舉轉換來說,還是很容易出錯的。所以,必須提供默認的值來確保轉換失敗時,返回正確的值。對於int值和string值轉換成Enum的代碼如下:

        public static T ToEnum<T>(int value, T defaultT) where T : struct
        {
            string enumName = Enum.GetName(typeof(T), value);

            return ToEnum<T>(enumName, defaultT);
        }

        public static T ToEnum<T>(string enumName, T defaultT) where T : struct
        {
            if (string.IsNullOrWhiteSpace(enumName))
            {
                return defaultT;
            }

            T result;

            if (!Enum.TryParse<T>(enumName.Trim(), out result))
            {
                return defaultT;
            }

            if (Enum.IsDefined(typeof(T), result))
            {
                return result;
            }

            return defaultT;
        }


另外還提供了其他應用的方法,如將包含類型名稱前綴的字符串ExchangeType.All轉換成枚舉,同樣需要提供默認值來確保轉換結果的准確性,代碼如下:

        public static T TryParse<T>(string typeValue, T defaultValue, bool containsTypeName = false) where T : struct
        { 
            typeValue = (typeValue ?? string.Empty).Trim();

            if (containsTypeName)
            {
                int startIndex = typeValue.IndexOf(".");

                if (startIndex > 0 && typeValue.Length > startIndex + 1)
                {
                    typeValue = typeValue.Substring(startIndex + 1);
                }
            }

            return ToEnum<T>(typeValue, defaultValue);
        }

應用的話,比較簡單,ExchangeType type = EnumFieldProvider.TryParse<ExchangeType>("ExchangeType.", ExchangeType.All, true);

三、高級應用通用方式

對於下拉列表中,很多場景與枚舉有關,硬編碼也可以直接綁定。但是枚舉很多的時候是不是得寫很多代碼,而且並不一定保證代碼的正確性。與其這樣,那就寫一個通用的吧,大家都輕松:

        public static EnumFieldAttribute GetEnumAttribute(Type type)
        {
            if (type == null)
            {
                return null;
            }

            object[] customAttributes = type.GetCustomAttributes(typeof(EnumFieldAttribute), true);
            EnumFieldAttribute attribute = null;

            foreach (object attr in customAttributes)
            {
                attribute = attr as EnumFieldAttribute;

                if (attribute != null)
                {
                    return attribute;
                }
            }

            return null;
        }

        public static IList<EnumItem<T>> GetItems<T>(bool isSpecialRequired = false) where T : struct
        {
            var fields = typeof(T).GetFields(BindingFlags.Static | BindingFlags.Public);

            if (fields == null || fields.Count() == 0)
            {
                return new List<EnumItem<T>>();
            }

            var enumItems = new List<EnumItem<T>>();
            EnumFieldAttribute attribute = null;
            T currentValue;

            foreach (var field in fields)
            {
                object[] customAttributes = field.GetCustomAttributes(typeof(EnumFieldAttribute), true);
                foreach (object attr in customAttributes)
                {
                    attribute = attr as EnumFieldAttribute;

                    if (attribute != null)
                    {
                        if (attribute.IsSpecialRequired)
                        {
                            if (!isSpecialRequired)
                            {
                                continue;
                            }
                        }

                        currentValue = (T)field.GetValue(null);

                        enumItems.Add(new EnumItem<T>(currentValue, attribute.Desc));
                    }
                } 
            }

            return enumItems;
        }

        public static IList<EnumItem<T>> GetItems<T>(IList<T> entities) where T : struct
        {
            if (entities == null || entities.Count() == 0)
            {
                return new List<EnumItem<T>>();
            }

            var enumItems = new List<EnumItem<T>>();

            foreach (var entity in entities)
            {
                enumItems.Add(GetItem<T>(entity));
            }

            return enumItems;
        }

        public static string GetItemDescription<T>(T enumItem) where T : struct
        {
            var field = typeof(T).GetField(enumItem.ToString());

            if (field == null)
            {
                return string.Empty; 
            }

            object[] customAttributes = field.GetCustomAttributes(typeof(EnumFieldAttribute), true);
            foreach (object attr in customAttributes)
            {
                EnumFieldAttribute attribute = attr as EnumFieldAttribute;

                if (attribute != null)
                {
                    return attribute.Desc;
                }
            }

            return string.Empty; 
        }

        public static EnumItem<T> GetItem<T>(T enumItem) where T : struct
        {
            var field = typeof(T).GetField(enumItem.ToString());

            if (field == null)
            {
                return new EnumItem<T>(enumItem, enumItem.ToString());
            }

            object[] customAttributes = field.GetCustomAttributes(typeof(EnumFieldAttribute), true);
            foreach (object attr in customAttributes)
            {
                EnumFieldAttribute attribute = attr as EnumFieldAttribute;

                if (attribute != null)
                {
return new EnumItem<T>(enumItem, attribute.Desc);
                }
            }

            return new EnumItem<T>(enumItem, enumItem.ToString());
        }

對於方法public static IList<EnumItem<T>> GetItems<T>(bool isSpecialRequired = false) where T : struct,提供一個參數來篩選是否需要該參數,如以上定義的枚舉類型ExchangeType中的 EnumFieldAttribute("不限", true),其中EnumFieldAttribute("不限", true)第二個參數與isSpecialRequired參數一致。
測試代碼如下:

        [TestMethod()]
        public void GetItemsTest()
        {
            IList<EnumItem<ExchangeType>> actual = EnumFieldProvider.GetItems<ExchangeType>(true);
            Assert.AreEqual(actual.Count, 2);
            Assert.AreEqual(actual[0].Value, ExchangeType.All);
            Assert.AreEqual(actual[1].Value, ExchangeType.SZSE);
        }

        [TestMethod()]
        public void GetItemsWithFalseArgTest()
        { 
            IList<EnumItem<ExchangeType>> actual = EnumFieldProvider.GetItems<ExchangeType>();
            Assert.AreEqual(actual.Count, 1);
            Assert.AreEqual(actual[0].Value, ExchangeType.SZSE);
        }

返回的結果可以用於下拉列表,ListBox等相關控件值的綁定與顯示(由於明天還得上班,本文不提供,下篇隨筆提供)。

四、總結

對於細節方面,還是需要花時間和精力來總結的。用得多了,自然也就懂了,洗洗睡覺了...

今天又是7月1號,又是一個紀念日。4年前,6月26號畢業聯歡晚會后,哥開始正式工作的第一天也是7月1號。一轉眼,4年過去了,人生如戲...


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM