How do I check if more than one enum flag is set?

2020-05-24 19:56发布

I just want to know if exactly one enum flag is set, not which ones. My current thinking is to check if it is a power of 2. Is there a better way built into enum types?

[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
}

标签: c# enums
4条回答
贪生不怕死
2楼-- · 2020-05-24 20:15

If the enum doesn't define explicit combinations of flags, you can just check if the value is defined in the enum:

private bool ExactlynOneFlagSet(Foo myFoo)
{
    return Enum.IsDefined(typeof(Foo), myFoo);
}
查看更多
Emotional °昔
3楼-- · 2020-05-24 20:17

As Jacob explained in a comment your method is not correct at all. Personally I always avoid programming mathematically, especially when it comes to logic. So my solution would be something like "if I wanted to know the count is one, so count it and compare it to number one".

Here it is:

    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;
    }

And you can use it for your foo type like this:

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

I believe this methods could be written in a more generic way using Generics and type handling methods. However I included the methods for most common base types for enums which are int and byte. But you could also write the same for short and other types. Also you may just inline the code in your code. It is only one line of code.

Also using this method you could see if the number of set flags is two or more. The below code returns true if the count of set flags is equal to 'n'.

   Enum.GetValues(enumType).Cast<byte>().Count(v => (value & v) == v) == n;
查看更多
▲ chillily
4楼-- · 2020-05-24 20:23
private bool ExatlyOneFlagSet(Foo myFoo)
{
  return !myFoo.ToString().Contains(',');
}
查看更多
神经病院院长
5楼-- · 2020-05-24 20:25

Its a Bit operation!

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

The statement checks if the value of myFoo is not power of two. Or, vice versa, the statement (myFoo & (myFoo -1)) == 0 checks for power of two. The idea is that only single flag values will be power of two. Setting more than one flag will result in a non power of two value of myFoo.

More information can be found in this answer to a similar question: https://stackoverflow.com/a/1662162/2404788.

For more information about bit operations go to http://en.wikipedia.org/wiki/Bitwise_operation

查看更多
登录 后发表回答