243

Let's say I have this enum:

[Flags] enum Letters { A = 1, B = 2, C = 4, AB = A | B, All = A | B | C, } 

To check if for example AB is set I can do this:

if((letter & Letters.AB) == Letters.AB) 

Is there a simpler way to check if any of the flags of a combined flag constant are set than the following?

if((letter & Letters.A) == Letters.A || (letter & Letters.B) == Letters.B) 

Could one for example swap the & with something?

4
  • Shouldn't all read 'All = A | B | C'? Commented Aug 27, 2009 at 9:56
  • 4
    AB | C is equivalent to A | B | C because AB was defined as A | B before. Commented Aug 27, 2009 at 10:00
  • 3
    @Daniel Brückner - It is equivalent, but it is less readable. Especially if the enum was expanded. Commented Aug 27, 2009 at 10:03
  • True. I can change it for better reading. Commented Aug 27, 2009 at 10:41

18 Answers 18

238

In .NET 4 you can use the Enum.HasFlag method :

using System; [Flags] public enum Pet { None = 0, Dog = 1, Cat = 2, Bird = 4, Rabbit = 8, Other = 16 } public class Example { public static void Main() { // Define three families: one without pets, one with dog + cat and one with a dog only Pet[] petsInFamilies = { Pet.None, Pet.Dog | Pet.Cat, Pet.Dog }; int familiesWithoutPets = 0; int familiesWithDog = 0; foreach (Pet petsInFamily in petsInFamilies) { // Count families that have no pets. if (petsInFamily.Equals(Pet.None)) familiesWithoutPets++; // Of families with pets, count families that have a dog. else if (petsInFamily.HasFlag(Pet.Dog)) familiesWithDog++; } Console.WriteLine("{0} of {1} families in the sample have no pets.", familiesWithoutPets, petsInFamilies.Length); Console.WriteLine("{0} of {1} families in the sample have a dog.", familiesWithDog, petsInFamilies.Length); } } 

The example displays the following output:

// 1 of 3 families in the sample have no pets. // 2 of 3 families in the sample have a dog. 
Sign up to request clarification or add additional context in comments.

3 Comments

This does not address the OP question. You must still && multiple HasFlag operations to determine if any flags are set. So the question is does petsInFamily have either a Pet.Dog || Pet.Cat?
See Mr. Skeet's clear answer... HasFlags Multiple
Microsoft says: If enum contains 0 (zero), HasFlag is not correct working
193

If you want to know if letter has any of the letters in AB you must use the AND & operator. Something like:

if ((letter & Letters.AB) != 0) { // Some flag (A,B or both) is enabled } else { // None of them are enabled } 

7 Comments

As far as I can see, this does the job. And had the clearest comments. Doesn't compile though without a parenthesis around letter & Letters.AB. Edited that in there.
Also if I introduced a Letters.None, I assume you could swap that with the 0 for a less compare-with-magic-number look?
Of course. But I don't think the AND comparison with 0 can be thought as a magic number strictly.
also stackoverflow.com/questions/40211/how-to-compare-flags-in-c is a recommended answer as it checks against the item in question as opposed to checking if it equals 0
@danrichardson the problem with the check for the exact item is that it eliminates the case when a part of the compound value is set (either A, or B), which is not what the OP wants.
|
70

I use extension methods to write things like that :

if (letter.IsFlagSet(Letter.AB)) ... 

Here's the code :

public static class EnumExtensions { private static void CheckIsEnum<T>(bool withFlags) { if (!typeof(T).IsEnum) throw new ArgumentException(string.Format("Type '{0}' is not an enum", typeof(T).FullName)); if (withFlags && !Attribute.IsDefined(typeof(T), typeof(FlagsAttribute))) throw new ArgumentException(string.Format("Type '{0}' doesn't have the 'Flags' attribute", typeof(T).FullName)); } public static bool IsFlagSet<T>(this T value, T flag) where T : struct { CheckIsEnum<T>(true); long lValue = Convert.ToInt64(value); long lFlag = Convert.ToInt64(flag); return (lValue & lFlag) != 0; } public static IEnumerable<T> GetFlags<T>(this T value) where T : struct { CheckIsEnum<T>(true); foreach (T flag in Enum.GetValues(typeof(T)).Cast<T>()) { if (value.IsFlagSet(flag)) yield return flag; } } public static T SetFlags<T>(this T value, T flags, bool on) where T : struct { CheckIsEnum<T>(true); long lValue = Convert.ToInt64(value); long lFlag = Convert.ToInt64(flags); if (on) { lValue |= lFlag; } else { lValue &= (~lFlag); } return (T)Enum.ToObject(typeof(T), lValue); } public static T SetFlags<T>(this T value, T flags) where T : struct { return value.SetFlags(flags, true); } public static T ClearFlags<T>(this T value, T flags) where T : struct { return value.SetFlags(flags, false); } public static T CombineFlags<T>(this IEnumerable<T> flags) where T : struct { CheckIsEnum<T>(true); long lValue = 0; foreach (T flag in flags) { long lFlag = Convert.ToInt64(flag); lValue |= lFlag; } return (T)Enum.ToObject(typeof(T), lValue); } public static string GetDescription<T>(this T value) where T : struct { CheckIsEnum<T>(false); string name = Enum.GetName(typeof(T), value); if (name != null) { FieldInfo field = typeof(T).GetField(name); if (field != null) { DescriptionAttribute attr = Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) as DescriptionAttribute; if (attr != null) { return attr.Description; } } } return null; } } 

3 Comments

You could make it a bit tighter like so: where T : struct, IConvertible. Great code otherwise!
@HamishGrubijan, good point... and enums also implement IFormattable and IComparable. However, all numeric types implement those interfaces too, so it's not enough to exclude them
Thanks for sharing but you do not always need to check for enum. IsFlagSet(this Enum value, Enum flag) is sufficient.
57

There is the HasFlag method in .NET 4 or higher.

Check if the letter includes A OR B

letter.HasFlag(Letters.A) || letter.HasFlag(B); 

Check if the letter includes A AND B

letter.HasFlag(Letters.A | Letters.B); 

Comments

40

If you can use .NET 4 or higher than use HasFlag() method

examples

letter.HasFlag(Letters.A | Letters.B) // both A and B must be set 

same as

letter.HasFlag(Letters.AB) 

2 Comments

Are you sure bitwise OR makes it "both must be set" and not any?
bitwise OR would combine the values, so 1000 | 0010 becomes 1010, or both set
14

If it really annoys you, you can write a function like that:

public bool IsSet(Letters value, Letters flag) { return (value & flag) == flag; } if (IsSet(letter, Letters.A)) { // ... } // If you want to check if BOTH Letters.A and Letters.B are set: if (IsSet(letter, Letters.A & Letters.B)) { // ... } // If you want an OR, I'm afraid you will have to be more verbose: if (IsSet(letter, Letters.A) || IsSet(letter, Letters.B)) { // ... } 

3 Comments

The line return (value & flag) == flag; does not compile: "Operator '&' cannot be applied to operands of type 'T' and 'T'".
awe: The question was not about binary operations, the question was about simplifying the syntax of bitmask-related operations in C#. There are plenty of excellent binary operation related questions and answers on stackoverflow already, there is no need to repost them everywhere.
I should recommend that those unfamiliar with binary operations get familiar, as the scaffolding to hide it above actually makes things much less readable in my opinion. Of course my 'raw' solution below is currently not doing so well compared to the score of this solution, so people are voting their preferences and I have to respect that ;-)
14

To check if for example AB is set I can do this:

if((letter & Letters.AB) == Letters.AB)

Is there a simpler way to check if any of the flags of a combined flag constant are set than the following?

This checks that both A and B are set, and ignores whether any other flags are set.

if((letter & Letters.A) == Letters.A || (letter & Letters.B) == Letters.B) 

This checks that either A or B is set, and ignores whether any other flags are set or not.

This can be simplified to:

if(letter & Letters.AB) 

Here's the C for binary operations; it should be straightforward to apply this to C#:

enum { A = 1, B = 2, C = 4, AB = A | B, All = AB | C, }; int flags = A|C; bool anything_and_a = flags & A; bool only_a = (flags == A); bool a_and_or_c_and_anything_else = flags & (A|C); bool both_ac_and_anything_else = (flags & (A|C)) == (A|C); bool only_a_and_c = (flags == (A|C)); 

Incidentally, the naming of the variable in the question's example is the singular 'letter', which might imply that it represents only a single letter; the example code makes it clear that its a set of possible letters and that multiple values are allowed, so consider renaming the variable 'letters'.

4 Comments

Wouldn't anything_and_a, a_and_or_c_and_anything_else and both_ac_and_anything_else always be true? or am I missing something here?
In this case, you can see what flags has been initialised to. However, should flags not contain A, then (flags & A) would be 0, which is false. both_ac_and_anything_else ensures that both A and C are set, but ignores any other flags that are also set (e.g. its true whether B is set or not).
Hm, some of those ends up as numbers and not boolean in C# though. How would you convert them to boolean?
Its not implicitly converted for you? Zero is equiv to 'false', and all other values are 'true'.
7

How about

if ((letter & Letters.AB) > 0) 

?

2 Comments

Yes! This will filter on the A and B values, and ignore if C is included. So if it is >0, it is also A or B or AB.
This doesn't 100% work with signed values. != 0 is better than > 0 for this reason.
7

I created a simple extension method that does not need a check on Enum types:

public static bool HasAnyFlag(this Enum value, Enum flags) { return value != null && ((Convert.ToInt32(value) & Convert.ToInt32(flags)) != 0); } 

It also works on nullable enums. The standard HasFlag method does not, so I created an extension to cover that too.

public static bool HasFlag(this Enum value, Enum flags) { int f = Convert.ToInt32(flags); return value != null && ((Convert.ToInt32(value) & f) == f); } 

A simple test:

[Flags] enum Option { None = 0x00, One = 0x01, Two = 0x02, Three = One | Two, Four = 0x04 } [TestMethod] public void HasAnyFlag() { Option o1 = Option.One; Assert.AreEqual(true, o1.HasAnyFlag(Option.Three)); Assert.AreEqual(false, o1.HasFlag(Option.Three)); o1 |= Option.Two; Assert.AreEqual(true, o1.HasAnyFlag(Option.Three)); Assert.AreEqual(true, o1.HasFlag(Option.Three)); } [TestMethod] public void HasAnyFlag_NullableEnum() { Option? o1 = Option.One; Assert.AreEqual(true, o1.HasAnyFlag(Option.Three)); Assert.AreEqual(false, o1.HasFlag(Option.Three)); o1 |= Option.Two; Assert.AreEqual(true, o1.HasAnyFlag(Option.Three)); Assert.AreEqual(true, o1.HasFlag(Option.Three)); } 

Enjoy!

1 Comment

Performance wise? Enums performance and JIT compilation seems to be poor, at least last time I looked at it (.Net 4.7.2)
6

There are a lot of answers on here but I think the most idiomatic way to do this with Flags would be Letters.AB.HasFlag(letter) or (Letters.A | Letters.B).HasFlag(letter) if you didn't already have Letters.AB. letter.HasFlag(Letters.AB) only works if it has both.

Comments

6

You can use this extension method on enum, for any type of enums:

public static bool IsSingle(this Enum value) { var items = Enum.GetValues(value.GetType()); var counter = 0; foreach (var item in items) { if (value.HasFlag((Enum)item)) { counter++; } if (counter > 1) { return false; } } return true; } 

1 Comment

Think this is the first answer I read that actually answers the question correctly. ultimately this was basically what I was going to do but I was hoping for a built in method to check for a single flag instance.
4

Starting with .Net 4, you can use a shorthand version without explicitly specifying &:

if(Letters.AB.HasFlag(Letters.C)) 

3 Comments

Microsoft says: If enum contains 0 (zero), HasFlag is not correct working
@RamilAliyev: if I am not mistaken, Microsoft says: If enum contains 0 (zero), if you check for the 0 (zero) flag with Instance.HasFlag(flag), this will always return true. To check for the zero flag Equals(flag) method should be used. So, HasFlag() works correctly with enums containing zero value, but checking for the zero flag does not work with HasFlag().
@DhyMik I agree with you
3

Would this work for you?

if ((letter & (Letters.A | Letters.B)) != 0) 

Comments

0
if((int)letter != 0) { } 

3 Comments

You might the same mistake as I did - he wants to check if A or B is set but ignore C.
You don't need the cast if you're checking the enum against 0.
This would check if any of all of them was set, not if any of a combined enum was set.
0

You could just check if the value is not zero.

if ((Int32)(letter & Letters.AB) != 0) { } 

But I would consider it a better solution to introduce a new enumeration value with value zero and compare agains this enumeration value (if possible because you must be able to modify the enumeration).

[Flags] enum Letters { None = 0, A = 1, B = 2, C = 4, AB = A | B, All = AB | C } if (letter != Letters.None) { } 

UPDATE

Missread the question - fixed the first suggestion and just ignore the second suggestion.

1 Comment

You don't need the cast if you're checking the enum against 0.
0

There are two aproaches that I can see that would work for checking for any bit being set.

Aproach A

if (letter != 0) { } 

This works as long as you don't mind checking for all bits, including non-defined ones too!

Aproach B

if ((letter & Letters.All) != 0) { } 

This only checks the defined bits, as long as Letters.All represents all of the possible bits.

For specific bits (one or more set), use Aproach B replacing Letters.All with the bits that you want to check for (see below).

if ((letter & Letters.AB) != 0) { } 

1 Comment

You might the same mistake as I did - he wants to check if A or B is set but ignore C.
0

Can we find out easily and efficiently whether at least one flag is set?

Well, if you are satisfied with checking whether at least one flag bit is set, then yes!

Usage:

if (EnumHelper.HasAnyFlagBitsSet(letter)) 

Implementation:

public static class EnumHelper { static EnumHelper() { // Required to get correct behavior in GetNumericValue // Because we will overlap the enum type with a ulong, left-aligned if (!BitConverter.IsLittleEndian) throw new NotSupportedException("This type is only supported on little-endian architectures."); } /// <summary> /// <para> /// Returns whether the given enum value has any bits set that occurs in a defined flag for <typeparamref name="T"/>. /// </para> /// <para> /// Throws if the type parameter is not an enum type with the <see cref="FlagsAttribute"/>. /// </para> /// </summary> public static bool HasAnyFlagBitsSet<T>(T enumValue) where T : unmanaged, Enum { var numericValue = GetNumericValue(enumValue); // Take the value that has all the permitted bits set // Use & to keep only the corresponding bits from the input value // Check that the input value provided at least one such bit return (numericValue & FlagValueCache<T>.AllFlagsSetValue) != 0; } /// <summary> /// <para> /// Returns whether the given enum value has any bits set that are set in <paramref name="flags"/>. /// </para> /// <para> /// Throws if the type parameter is not an enum type with the <see cref="FlagsAttribute"/>. /// </para> /// </summary> public static bool HasAnyFlagBitsSet<T>(T enumValue, T flags) where T : unmanaged, Enum { var numericValue = GetNumericValue(enumValue); var numericFlags = GetNumericValue(flags); // Use & to keep only the bits present in flags // Check that the input value provided at least one such bit return (numericValue & flags) != 0; } // Actually, have a bonus method as well, since this is a common operation: /// <summary> /// <para> /// Returns whether the given enum value consists exclusively of defined flags for <typeparamref name="T"/>. /// The result is false if a bit is set that is not part of any value defined by <typeparamref name="T"/>. /// </para> /// <para> /// Throws if the type parameter is not an enum type with the <see cref="FlagsAttribute"/>. /// </para> /// </summary> public static bool HasDefinedFlags<T>(T enumValue) where T : unmanaged, Enum { var numericValue = GetNumericValue(enumValue); // Take the value that has all the permitted bits set // Use ~ to get a value with all the forbidden bits set // Use & to keep only the corresponding bits from the input value // Check that the input value provided no such forbidden bits return (numericValue & ~FlagValueCache<T>.AllFlagsSetValue) == 0; } /// <summary> /// <para> /// Returns the numeric value of the given <paramref name="enumValue"/>. /// </para> /// <para> /// The resulting <see cref="ulong"/> can be cast to the intended integral type, even if it is a signed type. /// </para> /// </summary> [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong GetNumericValue<T>(T enumValue) where T : unmanaged, Enum { Span<ulong> ulongSpan = stackalloc ulong[] { 0UL }; Span<T> span = MemoryMarshal.Cast<ulong, T>(ulongSpan); span[0] = enumValue; return ulongSpan[0]; } /// <summary> /// Statically caches a "full" flags value each enum type for which this class is accessed. /// </summary> internal static class FlagValueCache<T> where T : unmanaged, Enum { /// <summary> /// Each bit that is set in any of the type's defined values is also set in this value. /// </summary> public static ulong AllFlagsSetValue { get; } static FlagValueCache() { if (typeof(T).BaseType != typeof(Enum)) throw new Exception("The type parameter must be an enum type."); foreach (var value in (T[])Enum.GetValues(typeof(T))) AllFlagsSetValue |= GetNumericValue(value); } } } 

What does it mean that we are checking if at least one flag bit is set?

Well, this solution may fail to answer correctly for nonsensical enums like the following:

[Flags] public enum Nonsense { One = 1, // Eh, why does this value need TWO bits when those bits are NOT defined as individual values? TwoAndFour = 2 | 4, } 

Here, EnumHelper.HasAnyFlagBitSet((Nonsense)2) would return true, which is technically incorrect, since 2 is not a defined flag.

However, it works perfectly fine for all sensible flags enums, including ones with multi-flags:

[Flags] public enum Fine { One = 1, Two = 2, Four = 4, // Fine, and sensible, since these flags exist individually TwoAndFour = 2 | 4, } 

Comments

0

You can use the bitwise AND operator (&) directly on the combined flag constant and check if the result is not equal to zero.

Here's an example using the AB flag from your Letters enum:

if ((letter & Letters.AB) != 0) { // AB flag is set } 

This works because the bitwise AND operation will only produce a non-zero result if at least one of the flags in Letters. AB is set in the letter variable. If the result is zero, it means none of the flags in Letters. AB are set in letter.

You can apply the same approach to check for any other combined flag constant, such as All:

if ((letter & Letters.All) != 0) { // At least one flag from All is set } 

By using the bitwise AND operator in this way, you can simplify the check and avoid explicitly comparing against the flag constant itself.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.