博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
c# 二进制或算法实现枚举的HasFlag函数
阅读量:6114 次
发布时间:2019-06-21

本文共 2908 字,大约阅读时间需要 9 分钟。

在权限的管理中,常常会出现一个权限包含的现象。例如,有三种基本权限:职员A、职员B、职员C.在此基础上,有经理权限,它包括A和B两种权限;还有老板权限,包含A/B/C三种权限。

在代码中,我们可以用枚举来管理这些权限。

[Flags]public enum EnumHasFlag{    A = 1 << 0,    B = 1 << 1,    C = 1 << 2,    Manager = A | B,    Boss = A | B | C,}

这段代码的特点是,定义枚举是用了一个属性来限制[Flags],以及每个值都是用二进制递增来赋值。这样做的好处是,可以通过枚举的HasFlag函数来判断某一个权限是否包含另一个权限。

static void Main(string[] args){    var rightA = EnumHasFlag.Boss;    var rightB = EnumHasFlag.Manager;    if (rightA.HasFlag(EnumHasFlag.C)) Console.WriteLine("rightA can do this");    if (rightB.HasFlag(EnumHasFlag.C)) Console.WriteLine("rightB can do this");    Console.ReadKey();}

最终代码会输出:rightA can do this。这样,通过HasFlag就可以判断枚举值的包含关系,从而进行相应的权限指定和管理。

这样的效果,还可以用过二进制的或运算来实现。基本语句是source | target == source.某个数值A,与另一个数值B进行或运算之后的结果还是A的话,可以判断A包含B。

static void Main(string[] args){    var A = 1 << 0 | 1 << 1;    if ((A | (1 << 0)) == A) Console.WriteLine("A has 1<<0");    if ((A | (1 << 2)) != A) Console.WriteLine("A doesn't have 1<<2");}

代码的输出结果为:

A has 1<<0  

A doesn't have 1<<2

在了解逻辑的前提下,我们可以做如下的开关:

static void Main(string[] args){    ControlCenter(1 << 0 | 1 << 3);}static void ControlCenter(int input){    if ((input | (1 << 0)) == input) Console.WriteLine("Do 0");    if ((input | (1 << 1)) == input) Console.WriteLine("Do 1");    if ((input | (1 << 2)) == input) Console.WriteLine("Do 2");}

最终的输出结果可以自己下去测试一下。

本篇用两种方法来实现数值的包含关系管理。仔细的理解了实现的逻辑之后,可以用在很多地方。例如,我们可以将多个设置的是否值揉合成一个字段。形如'10111101',用最少的代码来管理这些设置信息。在选项很少而且对象的活动领域很小的情况下,可以考虑用二进制的或运算来实现。这样实现的优点是,可以不用单独建立枚举,代码量少很多;缺点是,代码的可读性差,调用灵活度也不如枚举的HasFlag,可扩展性也不强。

补充

下面有园友提出了source & target == target的判断算法,来判断source是否包含target。我觉得条件非常充分,而且整个思路比或运算更加清晰。后来查阅了其他的资料,发现对枚举中的1,2,4,8的理解,很多都是从这个算式出发。

static void Main(string[] args){    var xx = TestEnum.Manager;    if ((xx & TestEnum.A) == TestEnum.A) Console.WriteLine("Has A");    Console.ReadKey();}enum TestEnum{    A = 1 << 0,    B = 1 << 1,    C = 1 << 2,    Manager = A | B,    Boss = A | B | C,}

 

15.6.6补充:

用linq to ef做hasflag查询时,做了一个测试,结果很有趣:

var f1 = db.Where(x => !x.Status.HasFlag(FlagEnum.Deleted));var f2 = db.Where(x => ((int)x.Status & (int)FlagEnum.Deleted) != (int)FlagEnum.Deleted);var f3 = db.Where(x => x.Status.HasFlag(FlagEnum.Deleted));var f4 = db.Where(x => ((int)x.Status & (int)FlagEnum.Deleted) == (int)FlagEnum.Deleted);

对应的sql语句的where条件是:

f1

WHERE  NOT (((( CAST( [Extent1].[Status] AS int)) & ( CAST( 4 AS int))) =  CAST( 4 AS int)) AND ((CASE WHEN (( CAST( [Extent1].[Status] AS int)) & ( CAST( 4 AS int)) IS NULL) THEN cast(1 as bit) ELSE cast(0 as bit) END) = 0))

f2

WHERE  NOT ((4 = (( CAST( [Extent1].[Status] AS int)) & (4))) AND (( CAST( [Extent1].[Status] AS int)) & (4) IS NOT NULL))

f3

WHERE (( CAST( [Extent1].[Status] AS int)) & ( CAST( 4 AS int))) =  CAST( 4 AS int)

f4

WHERE 4 = (( CAST( [Extent1].[Status] AS int)) & (4))}

直接说明了HasFlag和source & target = target的关系。

 

欢迎纠正和补充。转载请注明出处:

转载于:https://www.cnblogs.com/icyJ/archive/2013/02/20/HasFlag.html

你可能感兴趣的文章
python模块之hashlib: md5和sha算法
查看>>
linux系统安装的引导镜像制作流程分享
查看>>
解决ros建***能登录不能访问内网远程桌面的问题
查看>>
pfsense锁住自己
查看>>
vsftpd 相关总结
查看>>
bash complete -C command
查看>>
解决zabbix 3.0中1151端口不能运行问题
查看>>
售前工程师的成长---一个老员工的经验之谈
查看>>
Get到的优秀博客网址
查看>>
dubbo
查看>>
【Git入门之四】操作项目
查看>>
老男孩教育每日一题-第107天-简述你对***的理解,常见的有哪几种?
查看>>
Python学习--time
查看>>
在OSCHINA上的第一篇博文,以后好好学习吧
查看>>
高利率时代的结局,任重道远,前途叵测
查看>>
Debian 6.05安装后乱码
查看>>
欢迎大家观看本人录制的51CTO精彩视频课程!
查看>>
IntelliJ IDEA中设置忽略@param注释中的参数与方法中的参数列表不一致的检查
查看>>
关于软件开发的一些感悟
查看>>
uva 10806
查看>>