枚举——你是那温柔的陷阱吗
最近在园子里看了两篇关于枚举的文章《小心枚举陷阱》和《温柔的枚举陷阱》,说的都是一个问题:前台绑定枚举,数据库中存储枚举的值,当枚举更新后,数据库中的值却没有更新,于是引起了一堆数据不对应的问题。
在系统中,我们肯定都遇到过用枚举来储存数据的情况,如下图,需要显示的是学历,但学历这东西毕竟不是经常改,所以就用枚举吧,放在数据库中,还要新建一张表,还要左联,太麻烦。
如是就有了以下代码:
public enum EStueType { 小学, 中学, 大学, }
然后数据库中存储的就是0、1、2,用来分别表示小学、中学、大学。
但后来,新的需求来了,需要将中学变为初中和高中。有人想当然,直接将“中学”改成“初中”,然后再在“初中”和“大学”之间加一个“高中”,编译无误,OK,挂到服务器上了。
后来客户反应,噫?我以前不是填的大学吗?现在怎么变成高中生了啊?管理员拿个VS编译半天,终于发现,原来添加了一个“高中”后,“高中”的值变为2 了,也就是说数据库中原来的所有学历为2(以前表示的是大学生),现在都变成高中生了。哎,都是这温柔的枚举惹的祸啊,于是开始摈弃枚举。
解决这个问题常用的做法有两种:
1.新建一张表,专门用来存储学历
2.接着用那温柔的枚举。
第一种方法很好的解决了这个问题,但问题在于会在数据库中新建表,并且是一张更新不多的表,另一个问题是如果数据量大时,左联会影响性能。
第二种方法就需要我们很好的解决枚举的问题了,下面我就讲我用枚举时的做法。
用枚举时我们也有两种做法:第一:将枚举显示赋值:如下:
public enum EStueType
{
小学=0,
中学=1,
大学=2,
}
OK,你要新加一个高中对吧,难不到我:
public enum EStueType
{
小学=0,
初中=1,
高中=3,
大学=2,
}
新问题:dbo查数据:select * from [表名],然后发现用户的学历这儿,一堆0123,想当然的他认为
0代表小学
1代表初中
2代表高中
3代表大学
OK,他接下的操作就极具危险性了:他要对所有的大学生进行一次“婚前性教育培训课”,结果...........
于是,我们想着,要不我们数据库中直接存储枚名称,而不是值,也就是表中学历字段直接存储如“大学”。
嗯,这个办法不错,问题都解决了。
但好像我们学编程的第一节课老师就说了:不要用中文。有两个原因:
1.中文占用更多的数据空间
2.中文编程总让人感觉不是那么专业
于是我就想:如何实现这样的效果呢:数据库中只存储英文名称:如University,别人一看就知道大学,但前台上,我要显示的是“大学”两个汉字,如下:
于是我就编写了一个枚举的通用类:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Data;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public class EnumUtils<Tenum>
{
public static DataTable GetAllEnums()
{
Type t = typeof(Tenum);
FieldInfo[] fieldInfoList = t.GetFields();
DataTable dt = new DataTable();
dt.Columns.Add("Text", typeof(string));
dt.Columns.Add("Value", typeof(string));
foreach (FieldInfo tField in fieldInfoList)
{
if (!tField.IsSpecialName)
{
DataRow dr = dt.NewRow();
dr["Value"] = tField.Name;
EnumDescriptionAttribute[] enumAttributelist = (EnumDescriptionAttribute[])tField.GetCustomAttributes(typeof(EnumDescriptionAttribute), false);
if (enumAttributelist != null && enumAttributelist.Length > 0)
{
dr["Text"] = enumAttributelist[0].Description;
}
else
{
dr["Text"] = tField.Name;
}
dt.Rows.Add(dr);
}
}
return dt;
}
public static string GetText(Tenum enumInstance)
{
Type t = typeof(Tenum);
FieldInfo[] fieldInfoList = t.GetFields();
string strReturn = string.Empty;
foreach (FieldInfo tField in fieldInfoList)
{
if (!tField.IsSpecialName && tField.Name.ToLower() == enumInstance.ToString().ToLower())
{
EnumDescriptionAttribute[] enumAttributelist = (EnumDescriptionAttribute[])tField.GetCustomAttributes(typeof(EnumDescriptionAttribute), false);
if (enumAttributelist != null && enumAttributelist.Length > 0)
{
strReturn = enumAttributelist[0].Description;
break;
}
}
}
return strReturn;
}
public static string GetValue(Tenum enumInstance)
{
Type t = typeof(Tenum);
FieldInfo[] fieldInfoList = t.GetFields();
string strReturn = string.Empty;
foreach (FieldInfo tField in fieldInfoList)
{
if (!tField.IsSpecialName && tField.Name.ToLower() == enumInstance.ToString().ToLower())
{
strReturn = tField.Name;
break;
}
}
return strReturn;
}
public static Tenum GetEnum(string Value)
{
Type t = typeof(Tenum);
FieldInfo field = t.GetField(Value);
return (Tenum)System.Enum.Parse(t, Value);
}
public static void BindListControl(ListControl listControl)
{
listControl.DisplayMember = "Text";
listControl.ValueMember = "Value";
listControl.DataSource = GetAllEnums();
}
}
[AttributeUsage(AttributeTargets.Enum | AttributeTargets.Field, AllowMultiple = false)]
public class EnumDescriptionAttribute : Attribute
{
private string description;
public string Description
{
get
{
return this.description;
}
}
public EnumDescriptionAttribute(string description)
: base()
{
this.description = description;
}
}
}
枚举申明时如下:
public enum EStueType
{
[EnumDescription("小学")]
Primaryschool,
[EnumDescription("初中")]
JuniorHighSchool,
[EnumDescription("大学")]
HighSchool,
[EnumDescription("大学")]
University
}
前台绑定时:EnumUtils<EStueType>.BindListControl(this.comboBox1);
获得绑定值时(枚举类型): EnumUtils<EStueType>.GetEnum(this.comboBox1.SelectedValue.ToString());;
获得显示值时(枚举显示名称):EnumUtils<EStueType>.GetText(EStueType.HighSchool);
示例效果如下:
OK,一切问题解决
示例下载地址:https://files.cnblogs.com/Deper/%e6%9e%9a%e4%b8%be%e6%93%8d%e4%bd%9c%e7%b1%bb%e7%a4%ba%e4%be%8b.rar