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

本文关键字:枚举 标志 设置 是否 何检查 检查 | 更新日期: 2023-09-27 18:21:03

我只想知道是否只设置了一个枚举标志,而不是设置了哪些。我目前的想法是检查它是否是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
}

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

这是一个位操作!

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

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

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

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

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

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

如果你使用的是.NET Core 3.0+,你可以使用PopCount,它会返回"1〃;uintulong中的位,并使用POPCNT CPU指令(如果CPU支持SSE4,则它将使用软件回退)。

public static bool ExactlyOneFlagSet(Foo foo)
{
    return BitOperations.PopCount((ulong)foo) == 1;
}
Foo one = Foo.Flag1;
Foo two = Foo.Flag1 | Foo.Flag2;
Console.WriteLine(ExactlyOneFlagSet(one)); //true
Console.WriteLine(ExactlyOneFlagSet(two)); //false

正如Jacob在评论中解释的那样,您的方法根本不正确。就我个人而言,我总是避免数学编程,尤其是在逻辑方面。所以我的解决方案应该是"如果我想知道计数是一,那么就计数并将其与第一进行比较"。

这是:

    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。但你也可以写同样的短和其他类型。此外,您可以在代码中内联代码。这只是一行代码。

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

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