40

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
}
mcintoda
  • 635
  • 1
  • 8
  • 10
  • I don't think it is a solution. `1010 != 0`, `1010 - 1 = 1001`, `1010 & 1001 = 1000`, and `1000 != 0`. – Jacob Jan 21 '12 at 00:29
  • Is there anything built into the Enums to detect if multiple flags set? – mcintoda Jan 21 '12 at 00:32
  • 1
    possible duplicate of [Best algorithm to count the number of set bits in a 32-bit integer?](http://stackoverflow.com/questions/109023/best-algorithm-to-count-the-number-of-set-bits-in-a-32-bit-integer) – Jacob Jan 21 '12 at 00:35
  • Wait, I'm a little confused-- are you asking how to find out if multiple flags are set or exactly one flag is set? The title of the post seems to conflict with the body. – Brian Rogers Jan 21 '12 at 00:48
  • 1
    @mcintoda why don't you accept answers!? i see in your profile that you never accepted an answer, what's more simple than clicking that v and give the answerers the reputation they deserve and have the SO site more organized!?!?!? – Shimmy Weitzhandler May 05 '13 at 15:22

5 Answers5

74

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

Community
  • 1
  • 1
Guido Zanon
  • 2,939
  • 26
  • 31
10

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);
}
Thomas Levesque
  • 286,951
  • 70
  • 623
  • 758
  • +1: This works, even if the enum explicitly defines combinations (`enum Foo { None = 0 , A = 1 , B = 2 , C = 4 , AB = A|B , BC = B|C , All = A|B|C , }`). Specifying one of the predefined combinations ( `Enum.IsDefined(typeof(Foo),Foo.A|Foo.B)` ) will yield `true`: it is in fact a defined value. – Nicholas Carey Jan 21 '12 at 00:54
  • @NicholasCarey, yes, it will return true for AB, but AB has more than one bit set... The OP wants to know if there is more than one bit set, not if the value is defined. – Thomas Levesque Jan 21 '12 at 01:01
  • Sorry Thomas... ive undo it. Its just that te idea of resolve a flag problem with enum methods doesnt like me to much... but your answer is correct in the end. – Guido Zanon Jan 21 '12 at 01:35
  • @MF., you can see it as a flag problem, or you can see it as an enum problem ;). Both approaches have their merits, but in this case your solution is clearly better. – Thomas Levesque Jan 21 '12 at 02:25
  • Your answer shouldn't always be true, sometimes the user can set a combined field in the enum: `Flag4 = Flag2 + Flag3`, your function will than return `true` which is incorrect. – Shimmy Weitzhandler May 05 '13 at 01:53
  • @Shimmy, I know, that's what I added a restriction: "If the enum doesn't define explicit combinations of flags" – Thomas Levesque May 05 '13 at 10:15
  • @ThomasLevesque oops, sorry didn't see it. – Shimmy Weitzhandler May 05 '13 at 15:18
8
private bool ExatlyOneFlagSet(Foo myFoo)
{
  return !myFoo.ToString().Contains(',');
}
itsme86
  • 19,266
  • 4
  • 41
  • 57
  • 1
    @MarkHall in .NET if more than one flag is set, the string representation of the enum is a comma-delimited list. – Brian Rogers Jan 21 '12 at 00:49
  • 1
    @MarkHall The Flags attribute make it show the individual value names separated by commas. You can go ahead and try it. – itsme86 Jan 21 '12 at 00:49
  • 4
    This seems dangerous because it relies on internal implementation details. – Brian J Feb 20 '15 at 16:45
3

If you're using .NET Core 3.0+, you can use PopCount, it returns the number of "1" bits in a uint or ulong and uses the POPCNT CPU instruction (if CPU supports SSE4, otherwise it'll use a software fallback).

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
Magnetron
  • 7,495
  • 1
  • 25
  • 41
0

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;
000
  • 807
  • 7
  • 14