31

I have four flags

Current = 0x1  
Past = 0x2  
Future = 0x4  
All = 0x7

Say I receive the two flags Past and Future (setFlags(PAST | FUTURE)). How can I tell if Past is in it? Likewise how can I tell that Current is not in it? That way I don't have to test for every possible combination.

Grace Note
  • 3,205
  • 4
  • 35
  • 55
Malfist
  • 31,179
  • 61
  • 182
  • 269

8 Answers8

47

If you want all bits in the test mask to match:

if((value & mask) == mask) {...}

If you want any single bit in the test mask to match:

if((value & mask) != 0) {...}

The difference is most apparent when you are testing a value for multiple things.

To test for exclusion:

if ((value & mask) == 0) { }
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
35

First of all - use enums with FlagAttribute. That's what it's for.

[Flags]
public enum Time
{
    None = 0
    Current = 1,
    Past = 2,
    Future = 4
    All = 7
}

Testing then is done like this:

if ( (x & Time.Past) != 0 )

Or this:

if ( (x & Time.Past) == Time.Past )

The latter will work better if "Past" was a combination of flags and you wanted to test them all.

Setting is like this:

x |= Time.Past;

Unsetting is like this:

x &= ~Time.Past;
Vilx-
  • 104,512
  • 87
  • 279
  • 422
  • Correct me if I'm wrong, I think 1 is not appropriate to be used as flag value? As any flag value (& Operator) with 1, result is still 1. – Roy Lee Jan 17 '13 at 15:58
  • 1
    @Roylee - not, that's a perfectly normal flag value. It corresponds to exactly one bit. And think about it - for example 4 & 1 = 0. – Vilx- Jan 17 '13 at 18:24
  • Icic. got it :) Then you got to make sure the rest of the flag value sets are *power of 2*, right? – Roy Lee Jan 17 '13 at 19:26
  • 2
    @Roylee - Exactly! :) Note that "None" and "All" are a bit different - they're not flags themselves, but rather combinations of flags. I could also make `PastOrPresent=3` because `1 & 2 = 3`. It only makes sense to add these for combinations that are often used together. It saves typing and avoids mistakes. – Vilx- Jan 18 '13 at 09:08
  • 2
    @Roylee - Aww, hell. I made a typo. It's supposed to be `1 | 2 = 3`. :) – Vilx- Jan 19 '13 at 08:31
12

You may also want to add an extension method like this

  enum states {
     Current = 0x1,
     Past = 0x2,
     Future = 0x4,
     All = 0x7
  };

  static bool Is(this states current, states value) {
     return (current & value) == value;
  }

then you can do:

 if(state.Is(states.Past)) {
    // Past
 }
Brian Rasmussen
  • 114,645
  • 34
  • 221
  • 317
9

If you use .NET 4 or later I prefer to do this, cleaner imao:

[Flags]
public enum Time
{
    None = 0
    Current = 1,
    Past = 2,
    Future = 4
}

myProp = Time.Past | Time.Future;

if (myProp.HasFlag(Time.Past))
{
    // Past is set...
}
Ogglas
  • 62,132
  • 37
  • 328
  • 418
6

An addendum to Marc Gravell and Vilx-'s answer:

Your flagged enum shouldn't specify the amount for "All", it should just include your existing values. This goes for any calculated values.

[Flags]
public enum Time
{
    None = 0,
    Current = 1,
    Past = 2,
    Future = 4,
    All = Current | Past | Future
}

Note that Vilx- removed the use of Hexadecimal for values. This is important because once you're past 0x8, your values will have to comply with Hex. You should just stay in decimal.

EDIT: I also want to add that you can use bit shifting rather than hex/decimal.

This looks like:

[Flags]
public enum Time
{
    None = 0,
    Current = 1,
    Past = 1 << 1, // 2, 10 binary
    Future = 1 << 2, // 4, 100 binary
 // Example = 1 << 3, // 8, 1000 binary
 // Example = 1 << 4, // 16, 10000 binary
    All = Current | Past | Future
}
Kody
  • 905
  • 9
  • 19
  • 1
    Could you use something like `Past = 1 << Current, Future = 1 << Past` instead of the hardcoded decimal values? – Narshe Oct 08 '21 at 09:59
  • @Narshe You could if that's what you prefer. Technically Current could also be `Current = 1 << 0` or `Current = 1 << None`, and as you said, `Past = 1 << Current`, `Future = 1 << Past` will work just as I had above. – Kody Nov 11 '21 at 20:25
4
if ((flags & PAST) == PAST)
{
  // PAST is there
}

if ((flags & CURRENT) != CURRENT)
{
  // CURRENT is not there
}
mmcdole
  • 91,488
  • 60
  • 186
  • 222
Misko
  • 2,044
  • 12
  • 15
0
(value & Current) == Current
Samantha Branham
  • 7,350
  • 2
  • 32
  • 44
0

I think what is missing is to take "all" but one

[Flags]
public enum Time
{
    None = 0,
    Current = 1,
    Past = 1 << 1, // 2, 10 binary
    Future = 1 << 2, // 4, 100 binary
    All = Current | Past | Future
}

Then with the above flags enum, you can do

var notNow= Time&~Time.Current;
Walter Verhoeven
  • 3,867
  • 27
  • 36