对枚举值(Enum)进行位操作(AND & OR)
对枚举值进行AND 和 OR 操作是 .Net 中最不常用的功能之一,在读了本文之后你将会发觉它其实也是一个比较有用的功能。
在做项目的时候我们可能经常会碰到这样一种情况:我们需要存储一些boolean值,然后在我们定义的类里面对应的添加一个Isxxxx 属性。比如说用户权限对象(IsAdmin,IsUser,IsPowerUser等)。创建和检查这样的一些相关属性,然后还要注意这些属性之间的组合,随着这样的属性数量的增加,我们会发觉编写和维护代码的工作量会相当的大而且容易出错。
对于以上情况位操作(AND和OR)就可以相当轻松的进行处理,注意AND和OR是位操作符,他们是在数字的二进制表示层上进行操作。
如果你对二进制数不熟悉,请先参考相关资料。
二进制数上的操作有很多种,我们这里只需要用到AND和OR.
枚举类型(Enum)中的所有值都是整数,把一个整数用二进制进行表示的时候,我们可以把每一位都当作是一个boolean值,这样一个整数就可以来存储一个boolean值的列表。
为了可以方便的实现这个功能,我们规定在枚举对象当中存储的值只能够是2的幂。
下面我们举个例子,我们定义一个枚举对象来决定到底把什么调料放在Pizza上面。
< Flags() > Public Enum Toppings ‘注意需要Flags标记 表明是位编码
None = 0 '务必定义一个等于0的枚举值
Pepperoni = 1
Mushrooms = 2
Onions = 4
Anchovies = 8
Peppers = 16
Pineapple = 32
End Enum
然后我们创建一个MakePizza的方法,它的输入参数是 Toppings枚举值
MakePizza(UseToppings as Toppings)
在MakePizza方法内部我们首先定义一个枚举变量(MyToppings),对所有我们需要的值进行OR操作,然后赋值给它。
Dim MyToppings as Toppings
MyToppings = Mushrooms OR Onions OR Peppers
现在存储在MyToppings中的值是22.
00000010 (Mushrooms - 2)
00000100 (Onions - 4)
00010000 (Peppers - 16)
--------―― OR
00010110 (22)
在MakePizza(UseToppings as Toppings)方法内部,我们需要判断到底是什么值产生了MyToppings(22)。
为了实现这个目的,我们把MyToppings与传入的UseTopping进行AND操作。任何非零的操作结果代表一个True值。
现在我们来测试一下,如果传入Pepperoni,
If UseToppings AND Toppings.Pepperoni Then
'添加 pepperonis
End If
操作结果是 0(false)
00010110 (UseToppings - 22)
00000001 (Pepperoni - 1)
-------- AND
00000000 (0)
如果传入Onions
结果是true(大于0)
00010110 (UseToppings - 22)
00000100 (Onions - 4)
-------- AND
00000100 (4)
通过这样的方法,我们可以节省了存储我们要表示的对象的存储空间(在数据库当中或者内存当中)
我们不用创建Pepperoni, Onions, Mushrooms等的true/false列,只要存储一个数字22就可以了
通过这个例子,大家可以举一反三,比如说应用在用户权限上面(Edit, ReadOnly, Admin等)
你可以创建一个用户权限的枚举,然后把他们存储在数据库的一列上就可以了。
我们还可以在sql语句内部充分利用这个方便性,比如说
SELECT * FROM AUTHORS
WHERE UserRight & P_UserRight > 0
我们把存储在列UserRight的值和传入参数值 P_UserRight进行 & 操作,来判断满足权限的列。
Note:对于Enum枚举类型我们可以利用它的ToString 方法和Parse方法
dim top as Toppings = Toppings.Pepperoni OR Toppings.Onions OR Toppings.Pineapple
Dim strTop as string = top.ToString()
strTop中存储的值就是 “Pepperonii,Onions,Pineapple”
枚举的ToString方法返回一个列表,列表中包含所有相对应的值,值与值之间以逗号分隔;
Parse方法
Dim top2 as Toppings = CType([Enum].Parse(GetType(Toppings), "Onions,Pineapple"),Toppings)