• 【tag】Enum.HasFlag 方法


    官方地址:https://msdn.microsoft.com/zh-cn/library/system.enum.hasflag.aspx

    参考文章:http://www.cnblogs.com/icyJ/archive/2013/02/20/HasFlag.html

    Enum.HasFlag 方法 的作用:确定当前实例中是否设置了一个或多个位域。

    using System;
    
    [Flags] public enum DinnerItems {
       None = 0,
       Entree = 1,
       Appetizer = 2,
       Side = 4,
       Dessert = 8,
       Beverage = 16, 
       BarBeverage = 32
    }
    
    public class Example
    {
       public static void Main()
       {
          DinnerItems myOrder = DinnerItems.Appetizer | DinnerItems.Entree |
                                DinnerItems.Beverage | DinnerItems.Dessert;
          DinnerItems flagValue = DinnerItems.Entree | DinnerItems.Beverage;
          Console.WriteLine("{0} includes {1}: {2}", 
                            myOrder, flagValue, myOrder.HasFlag(flagValue));
       }
    }
    // The example displays the following output:
    //    Entree, Appetizer, Dessert, Beverage includes Entree, Beverage: True

    在权限的管理中,常常会出现一个权限包含的现象。例如,有三种基本权限:职员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,
    }

    用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的关系。

  • 相关阅读:
    PAT (Basic Level) Practice (中文)1002 写出这个数 (20 分)
    PAT (Advanced Level) Practice 1001 A+B Format (20 分)
    BP神经网络(原理及MATLAB实现)
    问题 1676: 算法2-8~2-11:链表的基本操作
    问题 1744: 畅通工程 (并查集)
    链表的基本操作(创建链表,查询元素,删除元素,插入元素等)
    问题 1690: 算法4-7:KMP算法中的模式串移动数组
    问题 1923: [蓝桥杯][算法提高VIP]学霸的迷宫 (BFS)
    Hdu1372 Knight Moves (BFS)
    Problem 2285 迷宫寻宝 (BFS)
  • 原文地址:https://www.cnblogs.com/FH-cnblogs/p/6929497.html
Copyright © 2020-2023  润新知