公告:本文有最新补丁
在很多时候,我们需要定义和获取枚举值,然而感觉到不够爽的就是当我们需要向用户描述一个枚举值的时候非常的不方便。通常我们有以下几个解决方案:
- 使用 if 语句;
- 使用 switch 语句;
- 使用数组索引;
- 使用字典索引;
- ……
然而这些方案在实践过程中并非都一帆风顺,在项目较小时,使用以上的方案是明智的,也非常的简单、方便。可是在大型项目当中,当别人看到你的一大堆的 if-else、switch等语句的时候——绝对头晕!
这个时候,使用字典索引来解决这个问题还是非常好的,尤其是泛型字典。但问题是,它虽然可以通用、实现原理也很简单,但是如果在代码中定义一堆一堆的关于枚举值的自定义描述字典,总是让人感觉到不爽。
有人说了:“可以用数据库嘛!”。是的,可以使用数据库,但是为了开发一个轻量级项目定义这么个数据库有些浪费。
又有人说了:“可以利用 Attribute 特性!”。这个方案可行,但是无法支持 .Net Framework 或第三方代码中已经定义好的枚举值的描述。
还有人说了:“既然如此,两者结合就可以解决这个问题!”。好!事实上 YMind 的构思就是通过结合两种方案的优点来做的。
YMind 整合了很多先进的编程思想开发了几个专门解决这个问题的类,使用它们就可以完美的解决以上所有的问题。
在封装枚举值自定义描述的操作的时候,YMind查阅了很多的资料,也看到了很多朋友实现的优秀的方案,但总结起来还是有一些缺点的,例如:
- 有些方案不支持多语言;
- 有些方案不支持位域操作;
- 有些方案性能太差;
- 几乎所有的方案都不支持“第三方已定义的枚举值”;
问题总是有办法解决的,多语言、位域操作可以整合这些先人们的成就即可解决,支持“第三方已定义的枚举值”可以采用字典解决,而性能优化可以对代码进行重构。说起来容易,可做起来难!下面介绍一下具体实现。
一、使用 Attribute 特性:
要使用 Attribute 特性,就需要先实现一个自己的 Attribute 类,这个类就是作为枚举值自定义描述的,它可以支持无限的继承,这就意味着,开发者可以根据自己的情况为不同的枚举值定义更多更丰富的功能。
EnumDescriptionAttribute类的代码如下:
- // ===============================================================================
- // 产品名称:网鸟小刺客便捷工具箱
- // 产品作者:YMind Chan
- // 版权所有:网鸟IT技术论坛 颜铭工作室
- // ===============================================================================
- // Copyright © Htmlbird.Net. All rights reserved .
- // 官方网站:http://www.htmlbird.net/
- // 技术论坛:http://bbs.htmlbird.net/
- // ===============================================================================
- using System;
- namespace EnumDescriptionVictor.Modules
- {
- /// <summary>
- /// 指定枚举值的自定义描述信息。
- /// </summary>
- [AttributeUsage(AttributeTargets.Enum | AttributeTargets.Field, AllowMultiple = false, Inherited = true)]
- public class EnumDescriptionAttribute : Attribute
- {
- #region 构造函数
- /// <summary>
- /// 根据指定的默认描述信息初始化 <see cref="EnumDescriptionAttribute"/> 类的新实例。
- /// </summary>
- /// <param name="text">指定包含该枚举值的自定义描述信息的字符串。</param>
- public EnumDescriptionAttribute(string text)
- {
- if (text == null) throw new ArgumentNullException("text");
- if (text.Length == 0) throw new ArgumentOutOfRangeException("text");
- this.Text = text;
- }
- #endregion
- #region 公有属性
- /// <summary>
- /// 获取或设置默认描述信息。
- /// </summary>
- public string Text { get; set; }
- /// <summary>
- /// 获取或设置用户自定义选项。
- /// </summary>
- public object[] UserOptions { get; set; }
- #endregion
- }
- }
这个类很简单,就不需要解释什么了,如果看不懂,请面壁三分钟反省一下!
二、如何使用我们定义好的 EnumDescriptionAttribute?
假设有一个枚举值定义如下:
- /// <summary>
- /// 表示性别的枚举值。
- /// </summary>
- public enum GenderPreference
- {
- /// <summary>
- /// 未知或未指定。
- /// </summary>
- Unknown = 0,
- /// <summary>
- /// 男性。
- /// </summary>
- Males = 1,
- /// <summary>
- /// 女性。
- /// </summary>
- Females = 2,
- }
使用我们定义好的 EnumDescriptionAttribute:
- /// <summary>
- /// 表示性别的枚举值。
- /// </summary>
- public enum GenderPreference
- {
- /// <summary>
- /// 未知或未指定。
- /// </summary>
- [EnumDescription("未知")]
- Unknown = 0,
- /// <summary>
- /// 男性。
- /// </summary>
- [EnumDescription("男")]
- Males = 1,
- /// <summary>
- /// 女性。
- /// </summary>
- [EnumDescription("女")]
- Females = 2,
- }
看到了吧,很简单!
其实只要你了解什么是Attribute,就早已明白如何使用了!
三、如何获取为枚举值定义好的EnumDescriptionAttribute呢?
这个问题说起来比较复杂,而且是本篇文章的核心所在。因为实现的代码很多,所以封装成了一个类:EnumVictor<T>。这个类的封装,解决了我们一开始提到的所有的问题:
- 支持多语言;
- 支持位域操作;
- 支持“第三方已定义的枚举值”;
- 大大的优化了性能;
获取EnumDescriptionAttribute的方法的代码如下(摘自:EnumVictor<T>):
- private void _Initialize()
- {
- Array enumValues = Enum.GetValues(this.EnumType);
- foreach (Enum value in enumValues)
- {
- if (value is T == false) continue;
- T itemValue = (T)((object)value);
- if (this.DescriptionFilter != null && this.DescriptionFilter.Count > 0 && this.DescriptionFilter.ContainsKey(itemValue))
- {
- EnumDescriptionAttribute descAttribute = this._GetDescription(value.ToString());
- descAttribute.Text = this.DescriptionFilter[itemValue];
- this.Descriptions.Add(itemValue, descAttribute);
- }
- this.DefaultDescriptions.Add(itemValue, this._GetDescription(value.ToString()));
- }
- }
四、如何使用EnumVictor<T>?
首先我们需要初始化EnumVictor<T>,有以下两种方式:
方式一:为已添加了 EnumDescriptionAttribute 标记的枚举值初始化:
- EnumVictor<AnimalSign> AnimalSignEnumVictor = new EnumVictor<AnimalSign>();
方式二:为没有或无法添加 EnumDescriptionAttribute 标记的枚举值初始化(支持“第三方已定义的枚举值”):
- Dictionary<AnimalSign, string> AnimalSignFilter = new Dictionary<AnimalSign, string>();
- AnimalSignFilter.Add(AnimalSign.Boar, "猪猪");
- // ....
- EnumVictor<AnimalSign> AnimalSignEnumVictor = new EnumVictor<AnimalSign>(AnimalSignFilter);
获取自定义描述:
- AnimalSignEnumVictor.GetDescriptionValue(AnimalSign.Boar);
- // 返回:猪猪
以位域操作的形式获取枚举值的自定义描述:
- Global.UserRolesEnumVictor.GetBitFieldDescriptionValue(UserRoles.Test);
- // 指定值:Test
- // 位域值:DataCensor, DataEntry, LogonLock
- // 返回值:[数据审查员],[数据录入员],[禁止登录]
怎么样?很爽吧!
转载网址:http://www.ymind.net/Article/73.aspx