位运算符作用于位,并逐位执行操作。&、 | 和 ^ 的真值表如下所示:
假设如果 A = 60,且 B = 13,现在以二进制格式表示,它们如下所示:
A = 0011 1100
B = 0000 1101
A&B = 0000 1100 = 12
A|B = 0011 1101 = 61
A^B = 0011 0001 = 49
我想我已经把上面的三种位运算符的使用规则讲清楚了。但是它们在常日工作中到底有什么实际的用途呢?
结合枚举类型对位运算符进行实战
首先我们定义一个枚举类Permission:
public enum Permission
{
Create = 1,
Read = 2,
Update = 4,
Delete = 8
}
注意上面的代码,里面的枚举值是1,2,4,8.这样定义枚举值是有意义的,为我们后面进行位运算提供了必要条件。
如果有用户有创建,修改和阅读的权限,一般我们可能这样写:
var permissions = new List<Permission>
{
Permission.Create , Permission.Update , Permission.Read
};
然后把permissions赋给用户,用户有一个List<Permission>属性来保存自己所有的权限。
后面对用户检查权限是否包含修改权限时,一般这样写:
if (permissions.Exists(o => o == Permission.Update))
{
...
}
对于上面的逻辑,是没有问题的,但是如果我们使用位运算符就可以这样写。
给用户创建,修改和阅读的权限:
Permission permissions = Permission.Create | Permission.Update | Permission.Read;
对用户检查权限是否包含修改权限:
Permission permission = permissions & Permission.Update;
if (permission == Permission.Update)
{
...
}
对于上面使用位运算符的实现方式有很多好处:代码的性能更好,我们使用位运算直接在堆栈上操作,之前使用List<Permission>属性是保存在应用程序堆中的,性能不加,还会触发GC。
我们现在运行下面这段代码:
Permission permissions = Permission.Create | Permission.Update | Permission.Read;
Console.WriteLine(permissions.ToString());
运行结果是:7
对于运行结果我们可以理解为7=1+2+4。但是可读性不高,我们对Permission枚举类使用Flag特性:
[Flags]
public enum Permission
{
...
}
再次运行上面的代码,运行结果是:
Create, Read, Update
没加特性的只是单纯的从值上的相加,而加了特性的则是枚举上的相加,可读性更好。
我们使用这种方式对用户权限进行控制更加简洁,我们只需要给用户一个int值就可以反推出来用户有哪些权限。
比如某个用户的Permissions是6,那么6=2+4,所以这个用户的权限就是Read和Update。
这种用处很大,比如权限、执行状态等,都可以用一个int型保存到数据库中,后面可以反向推导出来更多信息。
本文回顾:
位运算符
枚举类型对位运算符实战
位运算性能更好
枚举类使用Flag特性
位运算在某些场景中更加简洁