适当使用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"
) {
//...
}
else
if
(xx ==
"1"
) {
//...
}
在显示数据的时候又出现这样的代码:
switch
(xx) {
case
"0"
:
return
"未审核"
;
case
"1"
:
return
"已审核"
;
}
这样的代码不仅不利于维护,而且,可读性也是非常的差。
使用enum改造
对于以上这类比较固定而且数据量又比较小的状态,可以选择使用enum来改造它,首先定义这么一个枚举类型:
enum
AuditState {
//未审核
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为枚举值的类型
class
EnumHelper<T, V>
where
T :
struct
where
V :
struct
{
private
static
IDictionary<T,
string
> enumAndDescriptionCache;
//描述信息缓存
private
static
IDictionary<V,
string
> valueAndDescriptionCache;
static
EnumHelper()
{
Initialize();
}
/// <summary>
/// 初始化
/// </summary>
private
static
void
Initialize()
{
Type type =
typeof
(T);
if
(!type.IsEnum)
throw
new
ArgumentException(
"Generic type must be an enumeration"
);
string
[] enumNames = Enum.GetNames(type);
V[] enumValues = Enum.GetValues(type)
as
V[];
T[] enums = Enum.GetValues(type)
as
T[];
int
l = enumNames.Length;
enumAndDescriptionCache =
new
Dictionary<T,
string
>(l);
valueAndDescriptionCache =
new
Dictionary<V,
string
>(l);
EnumDescriptionAttribute tempAttr;
string
temp;
for
(
int
i = 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>
private
static
EnumDescriptionAttribute GetDescriptionAttr(FieldInfo f)
{
EnumDescriptionAttribute[] attrs = f.GetCustomAttributes(
typeof
(EnumDescriptionAttribute),
false
)
as
EnumDescriptionAttribute[];
if
(attrs !=
null
&& attrs.Length > 0)
{
return
attrs[0];
}
return
null
;
}
/// <summary>
/// 获取枚举类型的描述
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public
static
string
GetDescription(T value)
{
string
description =
null
;
if
(enumAndDescriptionCache.ContainsKey(value))
enumAndDescriptionCache.TryGetValue(value,
out
description);
return
description;
}
/// <summary>
/// 获取枚举类型的描述
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public
static
string
GetDescriptionByValue(V value)
{
string
description =
null
;
if
(valueAndDescriptionCache.ContainsKey(value))
valueAndDescriptionCache.TryGetValue(value,
out
description);
return
description;
}
/// <summary>
/// 获取枚举类型所有值及描述
/// </summary>
public
static
IEnumerable<KeyValuePair<T,
string
>> EnumDescriptions
{
get
{
foreach
(KeyValuePair<T,
string
> temp
in
enumAndDescriptionCache)
{
yield
return
temp;
}
}
}
/// <summary>
/// 获取枚举类型所有值及描述
/// </summary>
public
static
IEnumerable<KeyValuePair<V,
string
>> ValueDescriptions
{
get
{
foreach
(KeyValuePair<V,
string
> temp
in
valueAndDescriptionCache)
{
yield
return
temp;
}
}
}
}
具体使用
对于数据绑定可以这样子做:
<
select
>
<
asp:Repeater
runat="server" id="xx">
<
ItemTemplate
>
<
option
value="<%# Eval("Key")%>"><%# Eval("Value")%></
option
>
</
ItemTemplate
>
</
asp:Repeater
>
</
select
>
后端代码:
x.DataSource = EnumHelper<AuditState,
int
>.ValueDescriptions;
x.DataBind();
对以上这种数据绑定可以专门封装成一个用户控件,以便重复利用。
显示数据的时候可以这样:
<
asp:Repeater
runat="server" id="xx">
<
ItemTemplate
>
<%#EnumHelper<
AuditState
, int>.GetDescription(Convert.ToInt32(Eval("fromdb..")))%>
</
ItemTemplate
>
</
asp:Repeater
>
判断的时候也可以很直观:
if
(xxxx == AuditState.Audited)
//...
当然,使用的这些存在类型转换的地方还有待优化,比如到int32类型的转换、到AuditState类型的转换,都可以通过对EnumHelper类进行修改来完成,这里只是为了演示,就不再具体了。
更多需求
以上的方法只能适用于一种语言中,假如还需要显示英文的描述,那么就需要对以上的类型进行调整了。比如可以为EnumDescriptionAttribute添加一个属性:
public
string
Description {
get
;
set
; }
public
string
EnDescription {
get
;
set
; }
或者是再创建一个名为EnEnumDescriptionAttribute的类型,无论是哪种方法,都需要在EnumHelper类里面做更多的调整了。
个人认为更好的做法是使用外部xml文件,EnumHelper根据需要加载相应语言的描述文件,如:
public
class
EnumDescriptionFileAttribute : Attribute
{
public
EnumDescriptionFileAttribute(
string
lang,
string
filepath)
{
this
.Lang = lang;
this
.Filepath = filepath;
}
public
string
Lang {
get
;
set
; }
public
string
Filepath {
get
;
set
; }
}
[EnumDescriptionFile(
"AuditState.xml"
)]
enum
AuditState {
UnAudit = 0,
Audited
}
class
EnumHelper...{
void
LoadDescriptionFile(lang...) {
//...
}
string
GetDescription(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(信息-摘要 ...
随机推荐
- WCF项目中出现常见错误的解决方法:基础连接已经关闭: 连接被意外关闭
在我们开发WCF项目的时候,常常会碰到一些莫名其妙的错误,有时候如果根据它的错误提示信息,一般很难定位到具体的问题所在,而由于WCF服务的特殊性,调试起来也不是那么方便,因此往往会花费不少时间来进行跟 ...
- C#开发Windows服务的基础代码
做项目需要对Windows服务进行操作,从网上找了一些资料,总结如下: (以下程序在程序中测试通过) using System; using System.Collections.Generic; u ...
- linux操作命令等积累
1,启动服务:两种方式: /etc/init.d/networking start /etc/init.d/mysql start #:service mysql start service ne ...
- Linux下快速设定ip bond
在计算机网路普及的初期,很多OS系统都使用的为单网卡方式,即一个网卡使用一个IP地址.随着网络要求的不断提高,我们可以对多个网卡进行绑定聚合当一个逻辑网络接口来使用,从而大幅提升服务器的网络吞吐(I/ ...
- redis sentinel 集群配置-主从切换
1.配置redis master,redis slave(配置具体操作见上文http://www.cnblogs.com/wangchaozhi/p/5140469.html). redis mast ...
- Bzoj 2038---[2009国家集训队]小Z的袜子(hose) 莫队算法
题目链接 http://www.lydsy.com/JudgeOnline/problem.php?id=2038 Description 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色 ...
- php中读写excel表格文件示例。
测试环境:php5.6.24.这块没啥兼容问题. 需要更多栗子,请看PHPExcel的examples.还是蛮强大的. 读取excel文件. 第一步.下载开源的PHPExcel的类库文件,官方网站是h ...
- 搭建自己的ngrok服务(国内直接可用http://qydev.com/#)
ngrok 服务可以分配给你一个域名让你本地的web项目提供给外网访问, 特别适合向别人展示你本机的web demo 以及调试一些远程的API (比如微信公众号,企业号的开发) ngrok的官方服务可 ...
- (转)JavaScript一:为什么学习JavaScript?
Web程序不论是B/S(Browser/Server)还是C/S(Client/Server)架构,分为客户端程序与服务器端程序两种.ASP.NET是开发服务器端程序的强大工具,但是有时候为了降低服务 ...
- swift学习笔记之-协议
//协议(Protocols) import UIKit /*协议(Protocols) 1.协议定义了一个蓝图,规定了用来实现某一特定任务或者功能的方法.属性,以及其他需要的东西 2.类.结构体或枚 ...