适当使用enum做数据字典 ( .net c# winform csharp asp.net webform )
在一些应用中,通常会用到很多由一些常量来进行描述的状态数据,比如性别(男、女),审核(未审核、已审核)等。在数据库中一般用数字形式来存储,比如0、1等。
不好的做法
经常看到一些应用(ps:最近又看到)没有把这类数据整理成一个数据字典,比如经常重复这样的html:
<select><option value="0">未审核</option><option value="1">已审核</option></select>
然后在后端逻辑判断的时候又用这样的代码:
if(xx =="0") {//...}elseif(xx =="1") {//...}
在显示数据的时候又出现这样的代码:
switch(xx) {case"0":return"未审核";case"1":return"已审核";}
这样的代码不仅不利于维护,而且,可读性也是非常的差。
使用enum改造
对于以上这类比较固定而且数据量又比较小的状态,可以选择使用enum来改造它,首先定义这么一个枚举类型:
enumAuditState {//未审核UnAudit = 0,//已审核Audited}
代表了审核的2种状态,这样在进行判断的时候就可以比较直观的看出来了。但是对于数据绑定,这样做还不够,所以我选择使用Attribute来描述:
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = false)]public class EnumDescriptionAttribute : Attribute{ public EnumDescriptionAttribute(string description) { this.Description = description; } public string Description { get; set; }} |
现在,关于审核状态的枚举类型就变成这样了:
enum AuditState { //未审核 [EnumDescription("未审核")] UnAudit = 0, //已审核 [EnumDescription("已审核")] Audited} |
然后可以通过取出它的值以及EnumDescription,来实现绑定,无论在可读性还是维护上都是方便许多。
使用缓存
由于获取EnumDescriptionAttribute值是需要通过反射来实现的,如果每次都反射调用,那么性能将会比较糟糕。另外,调用Enum.GetNames、Enum.GetValues以及具体的如AuditState.UnAudit.ToString()方法也都是需要反射的,所以也要注意。
在这里使用静态变量来缓存这些信息,并且利用了泛型的特性,保证每种枚举类型都有一个对应的缓存信息,代码如下:
//T为枚举类型,V为枚举值的类型classEnumHelper<T, V>whereT :structwhereV :struct{privatestaticIDictionary<T,string> enumAndDescriptionCache;//描述信息缓存privatestaticIDictionary<V,string> valueAndDescriptionCache;staticEnumHelper(){Initialize();}/// <summary>/// 初始化/// </summary>privatestaticvoidInitialize(){Type type =typeof(T);if(!type.IsEnum)thrownewArgumentException("Generic type must be an enumeration");string[] enumNames = Enum.GetNames(type);V[] enumValues = Enum.GetValues(type)asV[];T[] enums = Enum.GetValues(type)asT[];intl = enumNames.Length;enumAndDescriptionCache =newDictionary<T,string>(l);valueAndDescriptionCache =newDictionary<V,string>(l);EnumDescriptionAttribute tempAttr;stringtemp;for(inti = 0; i < l; i++){tempAttr = GetDescriptionAttr(type.GetField(enumNames[i]));temp = tempAttr ==null?string.Empty : tempAttr.Description;enumAndDescriptionCache.Add(enums[i], temp);valueAndDescriptionCache.Add(enumValues[i], temp);}}/// <summary>/// 获取枚举类型的描述信息,并加入到缓存中/// </summary>/// <param name="f"></param>/// <param name="value"></param>privatestaticEnumDescriptionAttribute GetDescriptionAttr(FieldInfo f){EnumDescriptionAttribute[] attrs = f.GetCustomAttributes(typeof(EnumDescriptionAttribute),false)asEnumDescriptionAttribute[];if(attrs !=null&& attrs.Length > 0){returnattrs[0];}returnnull;}/// <summary>/// 获取枚举类型的描述/// </summary>/// <param name="value"></param>/// <returns></returns>publicstaticstringGetDescription(T value){stringdescription =null;if(enumAndDescriptionCache.ContainsKey(value))enumAndDescriptionCache.TryGetValue(value,outdescription);returndescription;}/// <summary>/// 获取枚举类型的描述/// </summary>/// <param name="value"></param>/// <returns></returns>publicstaticstringGetDescriptionByValue(V value){stringdescription =null;if(valueAndDescriptionCache.ContainsKey(value))valueAndDescriptionCache.TryGetValue(value,outdescription);returndescription;}/// <summary>/// 获取枚举类型所有值及描述/// </summary>publicstaticIEnumerable<KeyValuePair<T,string>> EnumDescriptions{get{foreach(KeyValuePair<T,string> tempinenumAndDescriptionCache){yieldreturntemp;}}}/// <summary>/// 获取枚举类型所有值及描述/// </summary>publicstaticIEnumerable<KeyValuePair<V,string>> ValueDescriptions{get{foreach(KeyValuePair<V,string> tempinvalueAndDescriptionCache){yieldreturntemp;}}}}
具体使用
对于数据绑定可以这样子做:
<select><asp:Repeaterrunat="server" id="xx"><ItemTemplate><optionvalue="<%# Eval("Key")%>"><%# Eval("Value")%></option></ItemTemplate></asp:Repeater></select>
后端代码:
x.DataSource = EnumHelper<AuditState,int>.ValueDescriptions;x.DataBind();
对以上这种数据绑定可以专门封装成一个用户控件,以便重复利用。
显示数据的时候可以这样:
<asp:Repeaterrunat="server" id="xx"><ItemTemplate><%#EnumHelper<AuditState, int>.GetDescription(Convert.ToInt32(Eval("fromdb..")))%></ItemTemplate></asp:Repeater>
判断的时候也可以很直观:
if(xxxx == AuditState.Audited)//...
当然,使用的这些存在类型转换的地方还有待优化,比如到int32类型的转换、到AuditState类型的转换,都可以通过对EnumHelper类进行修改来完成,这里只是为了演示,就不再具体了。
更多需求
以上的方法只能适用于一种语言中,假如还需要显示英文的描述,那么就需要对以上的类型进行调整了。比如可以为EnumDescriptionAttribute添加一个属性:
publicstringDescription {get;set; }publicstringEnDescription {get;set; }
或者是再创建一个名为EnEnumDescriptionAttribute的类型,无论是哪种方法,都需要在EnumHelper类里面做更多的调整了。
个人认为更好的做法是使用外部xml文件,EnumHelper根据需要加载相应语言的描述文件,如:
publicclassEnumDescriptionFileAttribute : Attribute{publicEnumDescriptionFileAttribute(stringlang,stringfilepath){this.Lang = lang;this.Filepath = filepath;}publicstringLang {get;set; }publicstringFilepath {get;set; }}[EnumDescriptionFile("AuditState.xml")]enumAuditState {UnAudit = 0,Audited}classEnumHelper...{voidLoadDescriptionFile(lang...) {//...}stringGetDescription(lang...) {//...}}<lang value="zh-cn"><field name="UnAudit"value="未审核"/><field name="Audited"value="已审核"/></lang><lang value="en"><field name="UnAudit"value="UnAudit"/><field name="Audited"value="Audited"/></lang>
这个目前还只是想法,也许有空会去实现它。 |
或许这么做看起来会有些繁锁,但为了灵活性考虑,这样子去做还是值得的,另外也是看个人喜好了吧。 |
适当使用enum做数据字典 ( .net c# winform csharp asp.net webform )的更多相关文章
- 拦截asp.net输出流做处理, 拦截HTML文本(asp.net webForm版)
对已经生成了HTML的页面做一些输出到客户端之前的处理 方法的原理是:把Response的输出重定向到自定义的容器内,也就是我们的StringBuilder对象里,在HTML所有的向页面输出都变 成了 ...
- Ninject 在 Winform、 Asp.net MVC中连络EntityFramework的应用
Ninject 在 Winform. Asp.net MVC中连络EntityFramework的应用( 注入同一个DbContext的应用名人名言:科学是老老实实的东西,它要靠许许多多人民的劳动和智 ...
- WinForm中 Asp.Net Signalr消息推送测试实例
p{ text-align:center; } blockquote > p > span{ text-align:center; font-size: 18px; color: #ff0 ...
- 做个无边框winform窗体,并美化界面
今天下午程序写完,有些时间就搞下界面美化,做个无框窗体.首先把窗体的FormBorderStyle设置为None,就变成无框的啦,不过你会发现这样窗体上就没有原来的最大最小化和关闭按钮了哦,所以要自己 ...
- C#中正确使用enum做Key的姿势
C#中自定义enum,然后将其作为Dictionary的Key,通常的做法如下: using System; using System.Text; using System.Collections.G ...
- Dictionary里使用struct,enum做key
首先看下Dictionary的源码 public void Add (TKey key, TValue value) { if (key == null) throw new ArgumentNull ...
- 做个简单的RSS订阅(ASP.NET Core),节省自己的时间
0x01 前言 因为每天上下班路上,午休前,都是看看新闻,但是种类繁多,又要自己找感兴趣的,所以肯定会耗费不少时间. 虽说现在有很多软件也可以订阅一些自己喜欢的新闻,要安装到手机,还是挺麻烦的.所以就 ...
- log4net在WinForm和ASP.net下的设置
下载log4net.dll,放到bin目录下,然后引用到工程.下面说明配置和调用方法. 1.AssemblyInfo.cs末尾添加 [assembly: log4net.Config.XmlConfi ...
- C#、WinForm、ASP.NET - Md5散列加密
MD5值概念解释: 转载自:http://free0007.iteye.com/blog/2047163 所 谓MD5,即"Message-Digest Algorithm 5(信息-摘要 ...
随机推荐
- jQuery使用经验建议
在开发过很多 jQuery 插件以后,我慢慢的摸索出了一套开发jQuery插件比较标准的结构和模式.这样我就可以复制并粘贴大部分的代码结构,只要专注最主要的逻辑代码就行了. 使用相同的设计模式和架构也 ...
- 富客户端 wpf, Winform 多线程更新UI控件
前言 在富客户端的app中,如果在主线程中运行一些长时间的任务,那么应用程序的UI就不能正常相应.因为主线程要负责消息循环,相应鼠标等事件还有展现UI. 因此我们可以开启一个线程来格外处理需要长时间的 ...
- MVC5+EF6 入门完整教程13 -- 动态生成多级菜单
稍微有一定复杂性的系统,多级菜单都是一个必备组件. 本篇专题讲述如何生成动态多级菜单的通用做法. 我们不用任何第三方的组件,完全自己构建灵活通用的多级菜单. 需要达成的效果:容易复用,可以根据mode ...
- 第二讲:WCF介绍(2)
代码 https://yunpan.cn/cPns5DkGnRGNs 密码:3913 在上一讲中我们说到 在代码 当中 完成了 服务的寄宿. 这里我们说下 在实际的开发 当中 我们一般不会去 ...
- 点击div折叠
<!doctype html> <html> <head> <meta charset="utf-8"> <meta cont ...
- mysql-databaseython 3.4.0 with MySQL database
Phttp://shttp://stackoverflow.com/questions/23376103/python-3-4-0-with-mysql-databasetackoverflow.co ...
- dubbo管理控制台安装
官网提供的下载路径好像不能用了,我也是在网上找的包,现在提供下载路径:http://pan.baidu.com/s/1nvPHQvZ 下载下来了,把他解压到wabapps->ROOT里面,先把t ...
- 对Java并发编程的几点思考
1. Threads 和 Runnables 所有的现代操作系统都通过进程和线程来支持并发.进程是通常彼此独立运行的程序的实例,比如,如果你启动了一个Java程序,操作系统产生一个新的进程,与其他程序 ...
- php中的常用数组函数(五)(数组中获取键名集合)
array_keys($arr, $search_value, $strict); --数组中获取键名的集合. //参数1 要检索的数组:参数2 要检索的键值 默认NULL: 参数3 是否严格比较(= ...
- 2016年湖南省第十二届大学生计算机程序设计竞赛Problem A 2016 找规律归类
Problem A: 2016 Time Limit: 5 Sec Memory Limit: 128 MB Description 给出正整数 n 和 m,统计满足以下条件的正整数对 (a,b) ...