C# 枚举的flags 标志位应用

枚举有个特性叫标志位,使用方法如下

[Flags]
enum Foo
{
    a =1,
    b = 2, 
    c = 4, 
    d = 8
}

每个值需要为2的n次方,保证多个值的组合不会重复.

这样在判断其中一个枚举值c 是否在a,b,c这个范围中就可以简化写法

常规写法如下

var c = Foo.c;
if( c == Foo.a || c == Foo.b || c == Foo.c )
{

}

因为值为2的n次方,所以可以通过按位相与来得出是否在范围内

var c = Foo.c;
if( (c & ( Foo.a | Foo.b | Foo.c ) != c )
{

}

注意,如果c在范围内则结果等于c,否则结果为0

可以写个扩展方法

    public static class  EnumExtension
    {
        /// <summary>
        /// 判断该枚举是否在范围内  注意:该枚举类型需要有[Flags] 标注
        /// </summary>
        /// <param name="source">待比较的值</param>
        /// <param name="range">枚举范围</param>
        /// <returns></returns>
        public static bool IsIn(this Enum source, params Enum[] range)
        {
            if(range.Length == 0)
            {
                return false;
            }
            else if(range.Length == 1)
            {
                return source == range[0];
            }
            int r = Convert.ToInt32(range[0]);
            for (int i = 1; i < range.Length; i++)
            {
                r |= Convert.ToInt32(range[i]);
            }
            return !((Convert.ToInt32(source) & r) == 0);
        }
    }

调用如下

var c = Foo.c;
if(c.IsIn(Foo.a, Foo.b, Foo.c))
{
}

此外flags还会重写该枚举的ToString()

比如  由于3 = 1 | 2,所以3就相当于a|b

当对3强转为Foo后进行ToString会输出 a,b 而不是3

 这样简单组合就可以得到新的有效枚举值,这种设计在权限等方面应用很多.

比如linux的文件权限 read write execute,缩写为r w x,对应值为 4 2 1

当需要一个值为

可读可写,    r w, 4 | 2 = 6

可写可执行, w x, 2 | 1 = 3

可读可执行,  r x,  4 | 1 = 5

可读可写可执行 r w x, 4 | 2 | 1 = 7

当然,也可以加上命名指定枚举值组合,比如定义一个ac 来替代a|c

[Flags]
enum Foo
{
    a = 1,
    b = 2,
    c = 4,
    ac = a | c,
    d = 8
}
原文地址:https://www.cnblogs.com/turingguo/p/14078795.html