说说C#中的enum吧
enum,就是枚举类型,它是struct,int,single,double一样,都属于值类型,从ValueType类型中派生,存储在栈中。它在被创建时,不需要分配内在空间,所以对程序的性能是有好处的。
为啥要引入enum呢?一个原因,就是让程序更加安全,添加程序的可读性,提高开发的效率。
啥时用呢?当我们已经确定了变更的数量,功能时可以将变更一个个的枚举出来,这时用enum.
举个例子吧,有一个chart,它可以有三种类型显示方式,分别为line,bar和pie,用户可以随便去指定用哪种方式来显示,这时我们可以用变量来控制,也可以用类型更安全的枚举来控制,看吧。
namespace Constants { public class SystemConstant { public Constants.Webinfo ChartTypes { get; set; } public string Result; public string Create() { ChartTypes = Constants.Webinfo.Pie; switch (ChartTypes) { case Constants.Webinfo.Bar: Result = "bar"; // code statement //....... // ........ break; case Constants.Webinfo.Line: Result = "line"; break; case Constants.Webinfo.Pie: Result = "pie"; break; } return Result; } } public enum Webinfo { Pie, Bar, Line } }
看到了吧,红色的地方就是我的enum了,在调用时,用Constants.Webinfo.Bar,Constants.Webinfo.Line,或者 Constants.Webinfo.Pie去调用,类型更安全,不会出现写错字符的现象。
Flags enum的高级用法:
NET中Flags枚举的使用
问题1
从指定 enum中去掉一个元素和加一个元素和判断某个元素是否在元素集合里存在:
看代码:
OrderState enums = OrderState.CustomerCanceled | OrderState.CustomerOrdered | OrderState.CustomerQuery; //必须是具体的枚举类型,不能直接写Enum类型 enums = enums ^ OrderState.CustomerCanceled; //第一种方法,如果集合里有这个元素,然后就移除这个元素,如果没有,就把这个元素加到集合里 enums = enums & (~OrderState.ShowBorder); // 第二种方法,移除一个元素 enums=enums | OrderState.CustomerOrdered; //向枚举列表中增加一个元素 bool hasFlag = ((enums & OrderState.CustomerCanceled) != 0); //判断指定枚举元素是否在枚举列表中存在 Console.WriteLine(hasFlag);
问题2 将我们把复合的枚举集合以int类型存储在数据库中,然后我们怎么把这个int型的数值再转成一个枚举的组合呢?
看代码:
[Flags] public enum Role { admini = 1, user = 2, backup = 4, guest = 8, } Role enums2 = Role.admini | Role.user | Role.backup; enums2 = enums2 | Role.guest;//加元素 enums2 = enums2 ^ Role.guest;//移除元素 Console.WriteLine(((int)enums2).ToString());//输出所包含的枚举元素的值的和 int RoleSum=(int)enums2) //结果是7 //结果RoleSum里是否包括Role.admin这个枚举值 ,方法一,bool aa = enums2.HasFlag(RoleName.Employee); //查看指定元素 方法二: if ( ((Role)Enum.Parse(typeof(Role), RoleSum.ToString()) & Role.admin) != 0) // if ( ((Role)Enum.Parse(typeof(Role), RoleSum.ToString()) & Role.admin) == Role.admin) Console.WriteLine("包含它"); else Console.WriteLine("不包含它"); 方法三: [Flags] public enum enumstatus { male = 1, female = 2, both = 4, } enumstatus es; es = enumstatus.male | enumstatus.female; if ( (es & enumstatus.both) != 0) Console.WriteLine("包含它" + es.ToString()); else { Console.WriteLine("不包含它"); }
问题3 如果向一个枚举集合中添加元素呢,我是说一个空的枚举对象中添加元素!
Role enums2 = Role.admini | Role.user | Role.backup; //方法一,这是静态赋值 Role enums2=new Role(); //方法二,这是先定义一个枚举对象,然后动态向里面加值 enums2 = enums2 | Role.admini; //也可以这样加 enums2 |= Role.backup; //也可以这样加 enums2 |= Role.user;
问题4 如何将一个枚举的集合转换为一个字符串数组对象,并将它进行输出
/// <summary>
/// 字符串数组化需要验证的枚举集合
/// </summary>
RoleName enums2=RoleName.Admin | RoleName.Boss | RoleName.HR | RoleName.DeptMgr;//为role赋多个值
string[] enumNames = null;
enumNames = Regex.Split(enums2.ToString(), ", ");
if (enumNames.Length < 1)
{
new Exception("枚举的数量太少了!");
}
else
{
foreach (var name in enumNames)
{
Console.WriteLine(name);
}
}
Flags Enum的一些说明
.NET中的枚举我们一般有两种用法,一是表示唯一的元素序列,例如一周里的各天;还有就是用来表示多种复合的状态。这个时候一般需要为枚举加上[Flags]特性标记为位域,例如:
[Flags] enum Styles{ ShowBorder = 1, //是否显示边框ShowCaption = 2, //是否显示标题ShowToolbox = 4 //是否显示工具箱}
这样我们就可以用"或"运算符组合多个状态,例如:
myControl.Style = Styles.ShowBorder | Styles.ShowCaption;
这时myControl.Style枚举的值将变成 1+2=3,它的ToString()将变成"Styles.ShowBorder , Styles.ShowCaption"
这里我们可以解释为什么第三个值ShowToolbox可以为4,5..而不能为3。也就是说它的值不应该是前几项值的复合值。有一个比较简单的方法就是用2的n次方来依次为每一项赋值,例如 1,2,4,8,16,32,64.....
现在举个常见的Flags应用例子。例如一个简单的权限系统,有"Admin"和"User"两种角色,我们可以在表中放一个 varchar()字段,以文本形式存放权限字"Admin,User"。但是用Flags型枚举的话,我们就可以直接将 Roles.Admin | Roles.User 的值放在一个int字段里。
以下是关于枚举的一些常见操作:
将枚举的值变回枚举对象:
Styles style = (Styles) Enum.Parse(typeof(Styles), "4" ); // -> style = Styles.Toolbox;
检查枚举是否包含某个元素:
bool hasFlag = ((style & Styles.ShowBorder) != 0);
其实我们还会碰到一种情况,就是需要从组合状态中去掉一个元素。用"^"运算符可以做到:
Styles style = Styles.ShowBorder | Styles.ShowCaption; style = style ^ Styles.ShowBorder;
这个时候style的值就会变成 Styles.ShowCaption
但这里有一个很严重的问题(偶现在才发现)
我们这个时候再执行一次
style = style ^ Styles.ShowBorder;
按照我们的设想,这个时候 style 的值是 Styles.ShowCaption,不包含 Styles.ShowBorder,所以我们就算去掉这个元素,style应该还是不会变。但实际的 style 的值却又变成了 Styles.ShowBorder | Styles.ShowCaption !! 再执行一遍,又会去掉这个元素,周而复始。
当然我们可以在去掉某个元素前做一番检查,如果枚举包含这个元素,再去掉它:
if ((style & Styles.ShowBorder) != 0){ style = style ^ Styles.ShowBorder; }
不知道有没有其它方法可以方便地从Flags枚举状态中去掉一个元素。。
Thanks to mobilebilly:
style = style & (~Styles.ShowBorder) 可以方便去掉一个元素。
好好利用枚举
这段时间手里有个有关订单的项目,订单一般有个状态的,以前很多要时候都会想到订单的状态就那几个种,就把它写死吧,不用一个数据库表了,太浪费资源了,但写死了用一个数字来代表一种订单状态,这样在编码时还要记得什么数字代码什么状态,如果不小心把它写错了,会导致数据出错。
后来想到.NET有个枚举,这么好的东西为何不用上来呢,这不但可以方便以后的代码维护,也方便编码。
public enum OrderState { /**//// <summary> /// 无效状态 /// </summary> Invalid = 0, /**//// <summary> /// 客户询价 /// </summary> CustomerQuery = 1, /**//// <summary> /// 客户落单 /// </summary> CustomerOrdered = 2, /**//// <summary> /// 客户付款 /// </summary> ReceiverCustomerPayment = 4, /**//// <summary> /// 向供货商订货 /// </summary> SupplierOrdered = 8, /**//// <summary> /// 供货商确认货期 /// </summary> SupplierOrderTerm = 16, /**//// <summary> /// 收到货品 /// </summary> RecieverGoods = 32, /**//// <summary> /// 客户取消订单 /// </summary> CustomerCanceled = 64, /**//// <summary> /// 供货商取消订单 /// </summary> SupplierCancelded = 128 }