如何检查是否设置了多个枚举标志?

时间:2012-01-21 00:17:55

标签: c# enums

我只想知道是否设置了一个枚举标志,而不是哪个。我目前的想法是检查它是否是2的幂。在枚举类型中是否有更好的方法?

[Flags]
enum Foo
{
Flag1 = 0x01,
Flag2 = 0x02,
Flag3 = 0x04,
Flag4 = 0x08,
Flag5 = 0x10,
Flag6 = 0x20,
Flag7 = 0x40,
Flag8 = 0x80
}

private bool ExactlynOneFlagSet(Foo myFoo)
{
  var x = (byte) myFoo;
  return (x != 0) && ((x & (x - 1)) == 0); //Check if a power of 2
}

if(!ExactlynOneFlagSet(Foo myFoo))
{
   //Do something
}

5 个答案:

答案 0 :(得分:60)

它的Bit操作!

if ((myFoo & (myFoo -1)) != 0) //has more than 1 flag

该语句检查myFoo的值是否不是2的幂。或者,反之亦然,声明(myFoo & (myFoo -1)) == 0检查2的幂。这个想法是只有单个标志值将是2的幂。设置多个标志将导致两个值为myFoo的非幂。

在类似问题的答案中可以找到更多信息:https://stackoverflow.com/a/1662162/2404788

有关位操作的更多信息,请转至http://en.wikipedia.org/wiki/Bitwise_operation

答案 1 :(得分:11)

private bool ExatlyOneFlagSet(Foo myFoo)
{
  return !myFoo.ToString().Contains(',');
}

答案 2 :(得分:8)

如果枚举没有定义标记的显式组合,您只需检查该值是否在枚举中定义:

private bool ExactlynOneFlagSet(Foo myFoo)
{
    return Enum.IsDefined(typeof(Foo), myFoo);
}

答案 3 :(得分:0)

雅各布在评论中解释说你的方法根本不正确。我个人总是避免数学编程,特别是在逻辑方面。所以我的解决方案就是“如果我想知道计数是一个,那就算一下,把它与第一个进行比较”。

这是:

    public static bool OneIsSet(Type enumType, byte value)
    {
        return Enum.GetValues(enumType).Cast<byte>().Count(v => (value & v) == v) == 1;
    }

    public static bool OneIsSet(Type enumType, int value)
    {
        return Enum.GetValues(enumType).Cast<byte>().Count(v => (value & v) == v) == 1;
    }

你可以将它用于你的foo类型:

   var toReturnFalse = (byte)(foo.Flag1 | foo.Flag2);
   var toReturnTrue = (byte)foo.Flag1;
   var trueWillBeReturned = OneIsSet(typeof(foo), toReturnTrue);
   var falseWillBeReturned = OneIsSet(typeof(foo), toReturnFalse);

我相信这些方法可以使用泛型和类型处理方法以更通用的方式编写。但是我为枚举的大多数常见基类型包括了int和byte的方法。但你也可以写短文和其他类型。 您也可以在代码中内联代码。它只有一行代码。

同样使用此方法,您可以查看设置标志的数量是否为两个或更多。如果set flags的计数等于'n',则下面的代码返回true。

   Enum.GetValues(enumType).Cast<byte>().Count(v => (value & v) == v) == n;

答案 4 :(得分:0)

如果您使用的是.NET Core 3.0+,则可以使用PopCount,它返回uintulong中的“ 1”位数,并使用{{ 1}} CPU指令(如果CPU支持SSE4,否则它将使用软件后备)。

POPCNT
public static bool ExactlyOneFlagSet(Foo foo)
{
    return BitOperations.PopCount((ulong)foo) == 1;
}