[转]用反射+特性列出所有的枚举变量及其描述信息,绑定到DropDownList上。
1。问题
在设计实体类的时候,通常我们会把某些字段设置为枚举值,例如性别:
这样好处不用说,通常是为了直观的考虑,还有限制输入的好处;如果强制用int转换,还以用System.Enum.IsDefined() 来判断枚举是否被定义,但是麻烦的是在界面UI上绑定的时候,我们通常要这样写:
然后如果要取得枚举的值,则:
这样虽然2的问题解决了,1、3还是没有解决。
解决的办法是,使用
来获得所有的枚举值,然后用foreach调用:
/// <summary>
/// 获得某个Enum类型的绑定列表
/// </summary>
/// <param name="enumType">枚举的类型,例如:typeof(Sex)</param>
/// <returns>
/// 返回一个DataTable
/// DataTable 有两列: "Text" : System.String;
/// "Value" : System.Char
/// </returns>
public static DataTable EnumListTable(Type enumType)
{
if(enumType.IsEnum != true)
{ //不是枚举的要报错
throw new InvalidOperationException();
}
//建立DataTable的列信息
DataTable dt = new DataTable();
dt.Columns.Add("Text",typeof(System.String));
dt.Columns.Add("Value",typeof(System.Char));
//获得特性Description的类型信息
Type typeDescription = typeof(DescriptionAttribute);
//获得枚举的字段信息(因为枚举的值实际上是一个static的字段的值)
System.Reflection.FieldInfo[] fields = enumType.GetFields();
//检索所有字段
foreach(FieldInfo field in fields)
{
//过滤掉一个不是枚举值的,记录的是枚举的源类型
if(field.FieldType.IsEnum == true)
{
DataRow dr = dt.NewRow();
// 通过字段的名字得到枚举的值
// 枚举的值如果是long的话,ToChar会有问题,但这个不在本文的讨论范围之内
dr["Value"] = (char)(int)enumType.InvokeMember(field.Name,BindingFlags.GetField,null,null,null);
//获得这个字段的所有自定义特性,这里只查找Description特性
object[] arr = field.GetCustomAttributes(typeDescription,true);
if(arr.Length > 0)
{
//因为Description这个自定义特性是不允许重复的,所以我们只取第一个就可以了!
DescriptionAttribute aa = (DescriptionAttribute)arr[0];
//获得特性的描述值,也就是‘男’‘女’等中文描述
dr["Text"] = aa.Description;
}
else
{
//如果没有特性描述(-_-!忘记写了吧~)那么就显示英文的字段名
dr["Text"] = field.Name;
}
dt.Rows.Add(dr);
}
}
return dt;
}
在设计实体类的时候,通常我们会把某些字段设置为枚举值,例如性别:
public enum Sex:int
{
Male = 'M',Female = 'W',NotRestrict = 'A'
}
{
Male = 'M',Female = 'W',NotRestrict = 'A'
}
这样好处不用说,通常是为了直观的考虑,还有限制输入的好处;如果强制用int转换,还以用System.Enum.IsDefined() 来判断枚举是否被定义,但是麻烦的是在界面UI上绑定的时候,我们通常要这样写:
<asp:DropDownList Runat="server" id="ddlSex">
<asp:ListItem Value="M">男</asp:ListItem>
<asp:ListItem Value="W">女</asp:ListItem>
<asp:ListItem Value="A">不限</asp:ListItem>
</asp:DropDownList>
<asp:ListItem Value="M">男</asp:ListItem>
<asp:ListItem Value="W">女</asp:ListItem>
<asp:ListItem Value="A">不限</asp:ListItem>
</asp:DropDownList>
然后如果要取得枚举的值,则:
Sex sex = (Sex)ddlSex.SelectedValue.ToCharArray()[0];
取值的时候其实没有多大问题,问题在UI上面
- 首先要知道所有枚举的值:例如'W','M','A'等
- 需要知道枚举值的名称,通常使用中文,例如'男','女'等,界面设计人员无法确定使用什么中文描述。
- 枚举的项目改变的时候,所有的绑定都需要改变。
2。解决了吗?
解决描述的问题很简单,使用XML文档就可以了。
只要在项目输出的时候输出XML文档,并且文档的名字跟DLL的名字一致就可以了。
需要丰富枚举定义:
/// <summary>
/// 性别
/// </summary>
public enum Sex:int
{
/// <summary>
/// 男
/// </summary>
Male = 'M',
/// <summary>
/// 女
/// </summary>
Female = 'W',
/// <summary>
/// 不限
/// </summary>
NotRestrict = 'A'
}
/// 性别
/// </summary>
public enum Sex:int
{
/// <summary>
/// 男
/// </summary>
Male = 'M',
/// <summary>
/// 女
/// </summary>
Female = 'W',
/// <summary>
/// 不限
/// </summary>
NotRestrict = 'A'
}
这样虽然2的问题解决了,1、3还是没有解决。
解决的办法是,使用
System.Enum.GetValues(typeof(sex));
来获得所有的枚举值,然后用foreach调用:
ddlSex.Items.Clear();
foreach(Sex sex1 in System.Enum.GetValues(typeof(Sex)))
{
ListItem item = new ListItem(sex1.ToString(),((char)sex1).ToString());
ddlSex.Items.Add(item);
}
foreach(Sex sex1 in System.Enum.GetValues(typeof(Sex)))
{
ListItem item = new ListItem(sex1.ToString(),((char)sex1).ToString());
ddlSex.Items.Add(item);
}
这样1,3的问题就解决了!美中不足的是列表项显示的是英文,如果想要解决也未尝不可:
- 把枚举的项改成中文的(-_-!,这个也太.......)
- 使用 反射+特性(Attribute)解决!
3。最终解决办法!
首先,给枚举值加上特性描述
public enum Sex:int
{
[Description("男")]
Male = 'M',
[Description("女")]
Female = 'W',
[Description("不限")]
NotRestrict = 'A'
}
{
[Description("男")]
Male = 'M',
[Description("女")]
Female = 'W',
[Description("不限")]
NotRestrict = 'A'
}
然后使用反射来读这个值:
/// <summary>
/// 获得某个Enum类型的绑定列表
/// </summary>
/// <param name="enumType">枚举的类型,例如:typeof(Sex)</param>
/// <returns>
/// 返回一个DataTable
/// DataTable 有两列: "Text" : System.String;
/// "Value" : System.Char
/// </returns>
public static DataTable EnumListTable(Type enumType)
{
if(enumType.IsEnum != true)
{ //不是枚举的要报错
throw new InvalidOperationException();
}
//建立DataTable的列信息
DataTable dt = new DataTable();
dt.Columns.Add("Text",typeof(System.String));
dt.Columns.Add("Value",typeof(System.Char));
//获得特性Description的类型信息
Type typeDescription = typeof(DescriptionAttribute);
//获得枚举的字段信息(因为枚举的值实际上是一个static的字段的值)
System.Reflection.FieldInfo[] fields = enumType.GetFields();
//检索所有字段
foreach(FieldInfo field in fields)
{
//过滤掉一个不是枚举值的,记录的是枚举的源类型
if(field.FieldType.IsEnum == true)
{
DataRow dr = dt.NewRow();
// 通过字段的名字得到枚举的值
// 枚举的值如果是long的话,ToChar会有问题,但这个不在本文的讨论范围之内
dr["Value"] = (char)(int)enumType.InvokeMember(field.Name,BindingFlags.GetField,null,null,null);
//获得这个字段的所有自定义特性,这里只查找Description特性
object[] arr = field.GetCustomAttributes(typeDescription,true);
if(arr.Length > 0)
{
//因为Description这个自定义特性是不允许重复的,所以我们只取第一个就可以了!
DescriptionAttribute aa = (DescriptionAttribute)arr[0];
//获得特性的描述值,也就是‘男’‘女’等中文描述
dr["Text"] = aa.Description;
}
else
{
//如果没有特性描述(-_-!忘记写了吧~)那么就显示英文的字段名
dr["Text"] = field.Name;
}
dt.Rows.Add(dr);
}
}
return dt;
}
使用方法如下:
DataTable dt = EnumListTable(typeof(Sex));
ddlSex.DataSource = dt;
ddlSex.DataTextField = "Text";
ddlSex.DataValueField = "Value";
ddlSex.DataSource = dt;
ddlSex.DataTextField = "Text";
ddlSex.DataValueField = "Value";
怎么样?方便吧?而且这个是通用的函数,适合于所有Enum,
前提条件是枚举值的所占的空间大小最好不要超过int。还有就是记得写描述的值,呵呵。
来自:http://www.cnblogs.com/yzxchoice/archive/2006/09/29/518122.html