常用扩展之枚举扩展
項(xiàng)目在開(kāi)發(fā)的過(guò)程中,經(jīng)常會(huì)遇到一些前臺(tái)顯示和后臺(tái)代碼不相同的屬性,比如布爾類型和枚舉類型的屬性要轉(zhuǎn)換為相應(yīng)的中文說(shuō)明。而且,轉(zhuǎn)換也會(huì)有千變?nèi)f化的可能,轉(zhuǎn)換為一個(gè)下拉列表框和網(wǎng)格中的一個(gè)列就不一樣。
這個(gè)時(shí)候,可能會(huì)有幾種解決方案:最簡(jiǎn)單的就是使用switch語(yǔ)句,寫(xiě)成一個(gè)擴(kuò)展方法,然后在前臺(tái)綁定的時(shí)候使用擴(kuò)展方法解決。這種方法簡(jiǎn)單,但是沒(méi)遇到一種就得寫(xiě)一個(gè)擴(kuò)展方法,不具有通用性。
我這里要說(shuō)的是基于Attribute的一種比較通用的方案。我們都知道,.Net能夠在類的成員上添加特性(Attribute),增加一些我們自己定制的東西。所以,我就在枚舉的這些成員上加上了一個(gè)自定義的特性,保存我要轉(zhuǎn)換的中文注釋。我自定義的特性代碼如下:
/// <summary> /// 字段或?qū)傩缘闹形慕忉寣傩?/span> /// </summary> [Serializable] [AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = false)] public class Desc : Attribute { /// <summary> /// 獲得字段或?qū)傩缘闹形慕忉? /// </summary> /// <value>字段或?qū)傩缘闹形慕忉?</value> public string Value { get; private set; } /// <summary> /// 初始化創(chuàng)建一個(gè) <see cref="Desc"/> 類的實(shí)例, 用于指示字段或?qū)傩缘慕忉屨f(shuō)明. /// </summary> /// <param name="value">字段或?qū)傩缘慕忉屨f(shuō)明.</param> public Desc(string value) { Value = value; } }之后,通過(guò)反射獲取這個(gè)屬性,進(jìn)而獲取我編程的時(shí)候?yàn)槠涮砑拥闹形淖⑨尅W龀蓴U(kuò)展方法之后,就可以對(duì)所有的枚舉使用了。不過(guò)因?yàn)槭褂昧朔瓷?#xff0c;在密集調(diào)用的時(shí)候效率上會(huì)損失一點(diǎn),不知道各位有沒(méi)有更好的解決方案。
/// <summary> /// 獲得枚舉字段的特性(Attribute),該屬性不允許多次定義。 /// </summary> /// <typeparam name="T">特性類型。</typeparam> /// <param name="value">一個(gè)枚舉的實(shí)例對(duì)象。</param> /// <returns>枚舉字段的擴(kuò)展屬性。如果不存在則返回 <c>null</c> 。</returns> public static T GetAttribute<T>(this Enum value) where T : Attribute { FieldInfo field = value.GetType().GetField(value.ToString()); return Attribute.GetCustomAttribute(field, typeof(T)) as T; }我先說(shuō)明一下,C#里面所有的枚舉(enum)都是從Enum這個(gè)類繼承的。所以將Enum填在這里,就能在所有的枚舉實(shí)例上使用這個(gè)擴(kuò)展方法。
約束T類型必須從Attribute這個(gè)類繼承,是因?yàn)镃#中規(guī)定能夠追加在字段上的特性必須從Attribute類繼承。對(duì)于這一點(diǎn)不理解的話,通過(guò)Google搜索一下,應(yīng)該很快就可以得到答案。
經(jīng)過(guò)了這兩個(gè)準(zhǔn)備之后,只要我們?cè)诿杜e的成員上加上了特性,就能夠通過(guò)這個(gè)擴(kuò)展方法訪問(wèn)了,而且不局限于我提供的這個(gè)屬性。我這里舉個(gè)例子簡(jiǎn)單說(shuō)明一下:
/// <summary> /// 客戶狀態(tài) /// </summary> [Serializable] public enum CustomerStateType { /// <summary> /// [默認(rèn)值] 活動(dòng)狀態(tài)。 /// </summary> [Desc("活動(dòng)")] Active = 0, ? /// <summary> /// 終止?fàn)顟B(tài)。 /// </summary> [Desc("終止")] End = 1, }定義完了之后,我們就可以通過(guò)擴(kuò)展方法獲得這個(gè)所謂的“活動(dòng)”和“終止”了。代碼如下:
// 假設(shè)這里是經(jīng)過(guò)了一系列計(jì)算得到的結(jié)果。 CustomerStateType state = CustomerStateType.Active; ? // 這里是想要獲得的結(jié)果。 string result = string.Empty; ? // 這就是我向你們展示的部分。 Desc description = state.GetAttribute<Desc>(); if (description != null) result = description.Value;我這里對(duì)于密集調(diào)用還有一個(gè)解決方案,正是針對(duì)于文章開(kāi)始所說(shuō)的列表中的枚舉轉(zhuǎn)換。上述擴(kuò)展方法的調(diào)用雖然會(huì)損失一些效率,但是可以通過(guò)緩存來(lái)解決這個(gè)問(wèn)題。先給大家看最終的效果:
private static Dictionary<CustomerStateType, string> _customerState = null; /// <summary> /// 獲得客戶狀態(tài)字典 /// </summary> public static Dictionary<CustomerStateType, string> CustomerStates { get { if (_customerState == null) _customerState = Enum<CustomerStateType>.AsEnumerable() .ToDictionary(p => p, p => p.GetAttribute<Desc>().Value); ? return _customerState; } }可以看到這是一個(gè)靜態(tài)屬性,放在字典中。想要獲取的時(shí)候可以通過(guò)鍵獲得相應(yīng)的中文解釋。代碼中的Enum<>類是我從CoolCode那竊取了一點(diǎn)想法,用于將一個(gè)枚舉類型轉(zhuǎn)換為IEnumable<>的可迭代序列。其代碼如下:
/// <summary> /// T 類型枚舉列表 /// </summary> /// <typeparam name="T">枚舉類型</typeparam> public class Enum<T> : IEnumerable<T> { #region Business Methods /// <summary> /// 返回類型為 IEnumerable<T> 的輸入。 /// </summary> /// <returns>類型為 IEnumerable<T> 的序列。</returns> public static IEnumerable<T> AsEnumerable() { return new Enum<T>(); } #endregion ? #region IEnumerable<T> 成員 ? /// <summary> /// 返回一個(gè)循環(huán)訪問(wèn)集合的枚舉數(shù)。 /// </summary> /// <returns>可用于循環(huán)訪問(wèn)集合的 IEnumerator<T> 。</returns> public IEnumerator<T> GetEnumerator() { return Enum.GetValues(typeof(T)) .OfType<T>() .AsEnumerable() .GetEnumerator(); } ? #endregion ? #region IEnumerable 成員 ? /// <summary> /// 返回一個(gè)循環(huán)訪問(wèn)集合的枚舉數(shù)。 /// </summary> /// <returns>可用于循環(huán)訪問(wèn)集合的 IEnumerator 。</returns> IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } ? #endregion ? #region IEnumerable<T> 成員 ? /// <summary> /// 返回一個(gè)循環(huán)訪問(wèn)集合的枚舉數(shù)。 /// </summary> /// <returns> /// <returns>可用于循環(huán)訪問(wèn)集合的 IEnumerator<T> 。</returns> IEnumerator<T> IEnumerable<T>.GetEnumerator() { return GetEnumerator(); } ? #endregion }這個(gè)類很簡(jiǎn)單,就是將枚舉類型的所有成員以一個(gè)IEnumable的形式展示,但是并沒(méi)有做額外的工作。但就是這樣,使得我們有了強(qiáng)大的擴(kuò)展功能,比如上面我所做的那個(gè)緩存字典。
我還有點(diǎn)不放心的是,文中用到了很多微軟提供給我們的Linq擴(kuò)展方法,不知道大家能明白多少。不過(guò)沒(méi)關(guān)系,園子里的LINQ專題可以提供參考。相信這不是什么問(wèn)題!關(guān)于LINQ的東西,我不想過(guò)多的發(fā)表觀點(diǎn),這里用一句話表明吧:很強(qiáng)大,能讓你在.Net平臺(tái)上走得更遠(yuǎn)!
當(dāng)然,這個(gè)問(wèn)題的解決方案肯定不止上面我提到的這兩種,聰明的你肯定還有其它的更好的方法,不妨寫(xiě)出來(lái),讓大家分享一下。
轉(zhuǎn)載于:https://www.cnblogs.com/lenic/archive/2011/01/13/1934209.html
總結(jié)
- 上一篇: 《Python核心编程》第二版第36页第
- 下一篇: null和“”的理解