有没有办法判断枚举是否只设置了一个,多个或没有标志?

时间:2016-06-13 17:12:24

标签: c# enums enum-flags

我有一个这样定义的枚举:

[Flags]
public enum Orientation
{
    North = 1,
    North_East = 2,
    East = 4,
    South_East = 8,
    South = 16,
    South_West = 32,
    West = 64,
    North_West = 128
}

是否有通用的方法来判断是否设置了一个标志,多个标志还是没有标志? 我不关心枚举的价值,我只想知道设置了多少标志。

这不是用于计算位数的重复。如果我像这样初始化枚举并计算我得到的位数10.但是设置标志的数量将是8。

GeographicOrientation go = (GeographicOrientation) 1023;

6 个答案:

答案 0 :(得分:4)

您可以使用此代码:

>>> [str.format('a{0}', x) for x in xrange(1,6)]
['a1', 'a2', 'a3', 'a4', 'a5']
>>> ['a' + str(x) for x in xrange(1,6)]
['a1', 'a2', 'a3', 'a4', 'a5']

答案 1 :(得分:3)

var test = Orientation.North;
var flagCount = GetFlagCount(test);

public int GetFlagCount(Enum testValue)
{
    return Enum.GetValues(testValue.GetType()).Cast<Enum>().Count(testValue.HasFlag);
}

答案 2 :(得分:2)

如果您正在寻找&#34;最短的&#34;方式:

Orientation o = Orientation.East | Orientation.West;   // o.ToString() = "East, West"
var c = o.ToString().Split().Count(); 

甚至更短:

var c = (o + "").Split().Count(); 

<强>更新

要支持255以上的值,您可以使用任何丑陋的黑客:

Orientation o = (Orientation) 1023;   
var c = ((Orientation)(byte)o + "").Split().Count();
c = ((Orientation)((int)o & 255) + "").Split().Count();

或者只是将枚举定义为byte:

    [Flags]
    public enum Orientation : byte
    {
        North = 1,
        North_East = 2,
        East = 4,
        South_East = 8,
        South = 16,
        South_West = 32,
        West = 64,
        North_West = 128
    }

更新2 我个人不会在生产代码中使用字符串方法,特别是当需要一点位数时。

无论如何,我只是为了好玩而想到了另一个黑客。当设置一位时,Base 2 log将返回一个整数,当0设置时,将返回-Infinity,当设置一位以上时,将返回任何其他内容。例如

 Math.Log(0, 2 ) // -Infinity
 Math.Log(0, 64) // 6.0
 Math.Log(0, 65) // 6.0223678130284544

因此,(byte)go != 0可用于检查是否设置了任何标志,然后Math.Log((byte)go, 2) % 1 == 0检查是否只设置了一个标志。

但是,dasblinkenlight的解决方案似乎是最好的。

答案 3 :(得分:1)

脱离我的头顶:

underscored: true

答案 4 :(得分:0)

将值转换为int后,您可以通过简单的位技巧确定这一点:

int v =(int)enumValue;

  1. 如果v == 0,则没有设置标志
  2. 否则,如果((v-1)&v) == 0,则只设置一个标志
  3. 否则,设置多个标志。
  4. 唯一棘手的是#2。以下是一个解释:考虑一个二进制数,其中只有一位设置为1。然后减去1将进行以下更改:

      0000010000000
    -             1
      -------------
      0000001111111
    

    单独1后的所有零变为1 s,1变为零,其余位保持不变。 AND - vv-1生成零,因为两个数字之间的同一位置没有1对。

    如果有两个或更多1 s,则单独1左侧的位将保持不变。因此,按位1的结果中至少有一个位置会有AND

答案 5 :(得分:0)

  

这不是用于计算位数的重复。如果我像这样初始化枚举并计算我得到的位数10.但是设置标志的数量将是8。

请直接考虑此声明from MSDN

  

标志枚举用于屏蔽位字段并进行按位比较

如果您以某种方式设计或使用枚举,不允许使用按位运算计算标志数,那么您正在设计或使用枚举不正确。

    [Flags]
    public enum MyEnum
    {
        Foo = 1,
        Bar = 2,
        Bizz = 4,
        Buzz = 8,
        Boo = 16
    }


var foo = MyEnum.Foo | MyEnum.Foo | MyEnum.Bizz;
// foo == MyEnum.Foo | MyEnum.Bizz because setting the same flag twice does nothing

var bar = (MyEnum)27 // Some invalid combination
// bar == 27.  Why would you do this instead of MyEnum.Boo | MyEnum.Buzz | MyEnum.Bar | MyEnum.Foo

如果你正确地设计你的枚举,你可以计算标志,如果设置了多个标志,可以选择短路,因为继续计数将毫无意义。

        var foo = MyEnum.Foo | MyEnum.Bizz;
        int fooValue = (int)foo;
        int numberOfFlags = 0;

        while (fooValue > 0 && numberOfFlags < 2) // Stop counting if more than one flag since we don't need exact count
        {
            if ((fooValue & 1) == 1)
            {
                numberOfFlags++;
            }

            fooValue >>= 1;
        }

        Console.WriteLine(numberOfFlags);