Using Bitwise operators on flags
Solution 1
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) { }
Solution 2
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;
Solution 3
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
}
Solution 4
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...
}
Solution 5
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
}
Programatt
I am a programmer by day, and a tinkerer by night.
Updated on November 12, 2021Comments
-
Programatt over 2 years
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 ifPast
is in it? Likewise how can I tell thatCurrent
is not in it? That way I don't have to test for every possible combination. -
Dennis Kioko over 15 years@Marc Gravell, why would you post this comment and not edit the post for the guy?
-
Roy Lee over 11 yearsCorrect 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.
-
Vilx- over 11 years@Roylee - not, that's a perfectly normal flag value. It corresponds to exactly one bit. And think about it - for example 4 & 1 = 0.
-
Roy Lee over 11 yearsIcic. got it :) Then you got to make sure the rest of the flag value sets are power of 2, right?
-
Vilx- over 11 years@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
because1 & 2 = 3
. It only makes sense to add these for combinations that are often used together. It saves typing and avoids mistakes. -
Vilx- over 11 years@Roylee - Aww, hell. I made a typo. It's supposed to be
1 | 2 = 3
. :) -
Narshe over 2 yearsCould you use something like
Past = 1 << Current, Future = 1 << Past
instead of the hardcoded decimal values? -
Kody over 2 years@Narshe You could if that's what you prefer. Technically Current could also be
Current = 1 << 0
orCurrent = 1 << None
, and as you said,Past = 1 << Current
,Future = 1 << Past
will work just as I had above.