145

If I have a variable holding a flags enum, can I somehow iterate over the single-bit values in that specific variable? Or do I have to use Enum.GetValues to iterate over the entire enum and check which ones are set?

rene
  • 37,946
  • 78
  • 99
  • 132
  • If you have control over your API, avoid using bit flags. They're rarely a useful optimization. Using a struct with several public 'bool' fields is semantically equivalent but your code is dramatically simpler. And if you need to later, you can change the fields to properties that manipulate bit fields internally, encapsulating the optimization. – Jay Bazuzi Nov 13 '10 at 06:15
  • 3
    I see what you're saying, and in many cases it would make sense, but in this case, I'd have the same problem as the If suggestion...I'd have to write If statements for a dozen different bools instead of using a simple foreach loop over an array. (And since this is part of a public DLL, I can't do arcane things like just having an array of bools or what have you.) –  Nov 13 '10 at 06:32
  • 13
    "your code is dramatically simpler" -- totally the opposite is true if you're doing anything other than just testing individual bits ... loops and set operations become virtually impossible because fields and properties aren't first class entities. – Jim Balter Oct 18 '13 at 23:58
  • 3
    @nawfal "a bit" I see what you did there – stannius Dec 07 '18 at 16:47

17 Answers17

191
static IEnumerable<Enum> GetFlags(Enum input)
{
    foreach (Enum value in Enum.GetValues(input.GetType()))
        if (input.HasFlag(value))
            yield return value;
}
Greg
  • 21,917
  • 11
  • 55
  • 77
  • That's close to what I'm doing, though I hadn't thought of building my own enumerator (or known that I could). I'm still fairly new to C#, so this was definitely an educational response for me. Thanks! –  Nov 13 '10 at 06:59
  • 7
    Note that `HasFlag` is available from .NET 4 onwards. – Andreas Grech Mar 14 '13 at 12:58
  • 4
    This is great! But You can make it even simpler and easy to use. Just stick this as an extension method: `Enum.GetValues(input.GetType()).Cast().Where(input.HasFlag);` Then just: `myEnum.GetFLags()` :) – joshcomley Aug 16 '13 at 12:28
  • 3
    Great one-liner, josh, but it still suffers the problem of picking up multi-flag values (Boo) instead of only single-flag values (Bar, Baz), as in Jeff's answer, above. –  Mar 06 '14 at 10:32
  • 11
    Nice - watch out for None's though - e.g. Items.None from Jeff's answer will always be included – Ilan Dec 30 '14 at 15:44
  • 1
    Method signature should be `static IEnumerable GetFlags(this Enum input)` – Erwin Rooijakkers Mar 11 '15 at 17:11
  • Exclude the Items.None flag by creating the flag with value 0 (`var zeroFlag = Enum.Parse(input.GetType(), "0");`) and adding `!zeroFlag.Equals(value)` to the `HasFlag` check – Chaulky Apr 21 '16 at 17:48
  • `if (Convert.ToInt32(value) != 0 && input.HasFlag(value))` – gresolio Oct 21 '20 at 08:51
60

Here is a Linq solution to the problem.

public static IEnumerable<Enum> GetFlags(this Enum e)
{
      return Enum.GetValues(e.GetType()).Cast<Enum>().Where(e.HasFlag);
}
agritton
  • 1,010
  • 8
  • 14
41

There aren't any builtin methods to get each component as far as I know. But here's one way you can get them:

[Flags]
enum Items
{
    None = 0x0,
    Foo  = 0x1,
    Bar  = 0x2,
    Baz  = 0x4,
    Boo  = 0x6,
}

var value = Items.Foo | Items.Bar;
var values = value.ToString()
                  .Split(new[] { ", " }, StringSplitOptions.None)
                  .Select(v => (Items)Enum.Parse(typeof(Items), v));

// This method will always end up with the most applicable values
value = Items.Bar | Items.Baz;
values = value.ToString()
              .Split(new[] { ", " }, StringSplitOptions.None)
              .Select(v => (Items)Enum.Parse(typeof(Items), v)); // Boo

I adapted what Enum does internally to generate the string to instead return the flags. You can look at the code in reflector and should be more or less equivalent. Works well for general use cases where there are values which contain multiple bits.

static class EnumExtensions
{
    public static IEnumerable<Enum> GetFlags(this Enum value)
    {
        return GetFlags(value, Enum.GetValues(value.GetType()).Cast<Enum>().ToArray());
    }

    public static IEnumerable<Enum> GetIndividualFlags(this Enum value)
    {
        return GetFlags(value, GetFlagValues(value.GetType()).ToArray());
    }

    private static IEnumerable<Enum> GetFlags(Enum value, Enum[] values)
    {
        ulong bits = Convert.ToUInt64(value);
        List<Enum> results = new List<Enum>();
        for (int i = values.Length - 1; i >= 0; i--)
        {
            ulong mask = Convert.ToUInt64(values[i]);
            if (i == 0 && mask == 0L)
                break;
            if ((bits & mask) == mask)
            {
                results.Add(values[i]);
                bits -= mask;
            }
        }
        if (bits != 0L)
            return Enumerable.Empty<Enum>();
        if (Convert.ToUInt64(value) != 0L)
            return results.Reverse<Enum>();
        if (bits == Convert.ToUInt64(value) && values.Length > 0 && Convert.ToUInt64(values[0]) == 0L)
            return values.Take(1);
        return Enumerable.Empty<Enum>();
    }

    private static IEnumerable<Enum> GetFlagValues(Type enumType)
    {
        ulong flag = 0x1;
        foreach (var value in Enum.GetValues(enumType).Cast<Enum>())
        {
            ulong bits = Convert.ToUInt64(value);
            if (bits == 0L)
                //yield return value;
                continue; // skip the zero value
            while (flag < bits) flag <<= 1;
            if (flag == bits)
                yield return value;
        }
    }
}

The extension method GetIndividualFlags() gets all the individual flags for a type. So values containing multiple bits are left out.

var value = Items.Bar | Items.Baz;
value.GetFlags();           // Boo
value.GetIndividualFlags(); // Bar, Baz
Jeff Mercado
  • 113,921
  • 25
  • 227
  • 248
  • I'd considered doing a string split, but that's probably a lot more overhead than just iterating the entire enum's bit values. –  Nov 13 '10 at 05:50
  • Unfortunately by doing so, you'd have to test for redundant values (if to did not want them). See my second example, it would yield `Bar`, `Baz` and `Boo` instead of just `Boo`. – Jeff Mercado Nov 13 '10 at 05:59
  • Interesting that you're able to get Boo out of that, though that part's unnecessary (and in fact, a really bad idea :) ) for what I'm doing. –  Nov 13 '10 at 06:48
  • This looks interesting, but if I'm not misunderstanding, it would return Boo for the above enum, where I'd want to enumerate only the versions that aren't combinations of other values (i.e., the ones that are powers of two). Could that be done readily? I've been trying and I can't think of an easy way to identify that without resorting to FP math. –  Nov 13 '10 at 22:55
  • @Robin: You're right, the original would return `Boo` (the value returned using `ToString()`). I've tweaked it to allow only individual flags. So in my example, you can get `Bar` and `Baz` instead of `Boo`. – Jeff Mercado Nov 14 '10 at 00:25
  • Nice method for the individual flags! I'll copy this into my code and put it to use. –  Nov 15 '10 at 07:57
  • Just a note: I've changed the accepted answer flag, since this is the version I'm now using, though Greg's enumeration is certainly good too. –  Dec 01 '10 at 03:49
  • Note that if your enum has negative values (for example with Visual Studio extensibility framework, Microsoft.VisualStudio.Shell.Interop._VSRDTFLAGS) then the use of ulong and ToUInt64 here will cause problems. If you replace with long and ToInt64 then it'll handle enums with negative values. – Nerdtron Nov 06 '17 at 15:35
28

Coming back at this a few years later, with a bit more experience, my ultimate answer for single-bit values only, moving from lowest bit to highest bit, is a slight variant of Jeff Mercado's inner routine:

public static IEnumerable<Enum> GetUniqueFlags(this Enum flags)
{
    ulong flag = 1;
    foreach (var value in Enum.GetValues(flags.GetType()).Cast<Enum>())
    {
        ulong bits = Convert.ToUInt64(value);
        while (flag < bits)
        {
            flag <<= 1;
        }

        if (flag == bits && flags.HasFlag(value))
        {
            yield return value;
        }
    }
}

It seems to work, and despite my objections of some years ago, I use HasFlag here, since it's far more legible than using bitwise comparisons and the speed difference is insignificant for anything I'll be doing. (It's entirely possible they've improved the speed of HasFlags since then anyway, for all I know...I haven't tested.)

  • Just a note flag is initialized to an int should be to a ulong such as bits, should be initialized as *1ul* – forcewill Feb 27 '15 at 14:24
  • Thanks, I'll fix that! (I just went and checked my actual code and I'd already fixed it the other way around by specifically declaring it to be a ulong.) –  Feb 28 '15 at 04:57
  • 2
    This is the only solution I found that seems to also not suffer from the fact that if you have a flag with value zero, which should represent "None", other answers GetFlag() methods will return the YourEnum.None as one of the flags even if it isn't actually in the enum you are running the method on! I was getting weird duplicate log entries because methods were running more times than I expected when they had only one non-zero enum flag set. Thanks for taking the time to update and add in this great solution! – BrianH May 21 '15 at 20:12
  • `yield return bits;`? – Jaider Oct 05 '15 at 22:03
  • You could do that if you wanted to return the ulong instead of the enum, but then you'd have to change the return type of the function as well. –  Oct 07 '15 at 00:19
  • 1
    I wanted an "All" enum variable, for which I assigned ulong.MaxValue, so all bits are set to '1'. But your code hits an infinite loop, because flag < bits never evaluates to true (flag loops to negative and then gets stuck at 0). – Haighstrom Dec 31 '17 at 08:00
  • Interesting point. I've never had that issue, but I can see why that would be a problem. I imagine an additional check would take care of the problem. –  Jan 01 '18 at 20:53
18

Going off of @Greg's method, but adding a new feature from C# 7.3, the Enum constraint:

public static IEnumerable<T> GetUniqueFlags<T>(this T flags)
    where T : Enum    // New constraint for C# 7.3
{
    foreach (Enum value in Enum.GetValues(flags.GetType()))
        if (flags.HasFlag(value))
            yield return (T)value;
}

The new constraint allows this to be an extension method, without having to cast through (int)(object)e, and I can use the HasFlag method and cast directly to T from value.

C# 7.3 also added constraints to for delegates and unmanaged.

Leniel Maccaferri
  • 94,281
  • 40
  • 348
  • 451
AustinWBryan
  • 2,968
  • 3
  • 17
  • 35
  • 7
    You probably wanted the `flags` parameter to be of the generic type `T` too, otherwise you'd have to explicitly specify the enum type every time you call it. – Ray Oct 08 '19 at 13:28
  • @Ray: thanks much for the comment... just updated the code! :-) – Leniel Maccaferri Apr 28 '21 at 21:59
  • 1
    @LenielMaccaferri Thanks for the edit! Not sure why I didn't edit it right away back then... xD – Ray Apr 29 '21 at 14:16
13

+1 for the answer provided by @RobinHood70. I found that a generic version of the method was convenient for me.

public static IEnumerable<T> GetUniqueFlags<T>(this Enum flags)
{
    if (!typeof(T).IsEnum)
        throw new ArgumentException("The generic type parameter must be an Enum.");

    if (flags.GetType() != typeof(T))
        throw new ArgumentException("The generic type parameter does not match the target type.");

    ulong flag = 1;
    foreach (var value in Enum.GetValues(flags.GetType()).Cast<T>())
    {
        ulong bits = Convert.ToUInt64(value);
        while (flag < bits)
        {
            flag <<= 1;
        }

        if (flag == bits && flags.HasFlag(value as Enum))
        {
            yield return value;
        }
    }
}

EDIT And +1 for @AustinWBryan for bringing C# 7.3 into the solution space.

public static IEnumerable<T> GetUniqueFlags<T>(this T flags) where T : Enum
{
    ulong flag = 1;
    foreach (var value in Enum.GetValues(flags.GetType()).Cast<T>())
    {
        ulong bits = Convert.ToUInt64(value);
        while (flag < bits)
        {
            flag <<= 1;
        }

        if (flag == bits && flags.HasFlag(value as Enum))
        {
            yield return value;
        }
    }
}

Wallace Kelly
  • 11,917
  • 6
  • 37
  • 52
  • Your edited code was exactly what I was using until today. I've improved on the code yet again, using various tricks I've learned in the past few years. See my latest answer: https://stackoverflow.com/a/63760259/14160657 – RobinHood70 Sep 06 '20 at 03:06
3

What I did was change my approach, instead of typing the input parameter of the method as the enum type, I typed it as an array of the enum type (MyEnum[] myEnums), this way I just iterate through the array with a switch statement inside the loop.

ЯegDwight
  • 23,615
  • 10
  • 43
  • 51
Ragin'Geek
  • 31
  • 1
3

You dont need to iterate all values. just check your specific flags like so:

if((myVar & FlagsEnum.Flag1) == FlagsEnum.Flag1) 
{
   //do something...
}

or (as pstrjds said in comments) you can check for use it like:

if(myVar.HasFlag(FlagsEnum.Flag1))
{
   //do something...
}
Community
  • 1
  • 1
Dr TJ
  • 2,966
  • 31
  • 49
  • 5
    If you are using .Net 4.0 there is an extension method HasFlag that you can use to do the same thing: myVar.HasFlag(FlagsEnum.Flag1) – pstrjds Nov 13 '10 at 05:48
  • thank you... i've never seen what you say, but it should be so good... :) – Dr TJ Nov 13 '10 at 05:49
  • 1
    If a programmer can't understand a bitwise AND operation they should pack it up and find a new career. – Ed S. Nov 13 '10 at 05:54
  • 2
    @Ed: true, but HasFlag is better when you are reading code again... (maybe after some monthes or years) – Dr TJ Nov 13 '10 at 05:56
  • 4
    @Ed Swangren: It's really about making the code more readable and less verbose, not necessarily because using bitwise operations are "hard." – Jeff Mercado Nov 13 '10 at 06:02
  • 2
    HasFlag is tremendously slow. Try a large loop using HasFlag vs. bit-masking and you'll notice a huge difference. –  Nov 13 '10 at 06:18
  • 1
    As to the If statements, I would need to check each bit flag individually, and there are many. (I don't need to know if one specific condition is true, I need to take an action for each possible flag if it's set.) A foreach loop over an Enum.GetValues array makes a lot more sense than a dozen or so If statements. –  Nov 13 '10 at 06:23
  • @Robert: but, its the same... even you are paying for a conversion too with `GetValues` – Dr TJ Nov 13 '10 at 06:28
  • @Dr TJ: Huh? Are you saying that you will forget what (flags & Value) does in a couple of months? Really? Give me a break. – Ed S. Nov 13 '10 at 06:37
  • Ok, sorry, that came off more aggressive than I intended... my point is that bitwise operations are a core, fundamental concept and honestly, anyone who can't understand a simple AND operation at a glance is *not* a software engineer (though they may play one in real life) – Ed S. Nov 13 '10 at 06:40
  • The dozen or so if's might be faster, you're right, but the code would be ugly and I'd have to write new if statements if later versions expand the num. Maybe if I post my (as yet untested) code, it'll make more sense. I dunno if this'll format correctly, as you can tell, I'm new here... foreach (QueryTypes bitFlag in Enum.GetValues(typeof(QueryTypes))) if ((value & bitFlag) != QueryTypes.None) { QueryInfo qi = QueryDictionary[bitFlag]; Parameters[qi.PropertyType] += "|" + qi.PropertyName; } –  Nov 13 '10 at 06:43
2

Building upon Greg's answer above, this also takes care of the case where you have a value 0 in your enum, such as None = 0. In which case, it should not iterate over that value.

public static IEnumerable<Enum> ToEnumerable(this Enum input)
{
    foreach (Enum value in Enum.GetValues(input.GetType()))
        if (input.HasFlag(value) && Convert.ToInt64(value) != 0)
            yield return value;
}

Would anyone know how to improve upon this even further so that it can handle the case where all flags in the enum are set in a super smart way that could handle all underlying enum type and the case of All = ~0 and All = EnumValue1 | EnumValue2 | EnumValue3 | ...

Didier A.
  • 3,650
  • 2
  • 35
  • 38
2

Extension method using the new Enum constraint and generics to prevent casting:

public static class EnumExtensions
{
    public static T[] GetFlags<T>(this T flagsEnumValue) where T : Enum
    {
        return Enum
            .GetValues(typeof(T))
            .Cast<T>()
            .Where(e => flagsEnumValue.HasFlag(e))
            .ToArray();
    }
}
Saeb Amini
  • 19,545
  • 8
  • 69
  • 71
2

Continuing in my efforts to make the code shorter, this is my latest version of the routine. (I'm the OP...long story.) As discussed previously, this ignores None and multi-bit values.

Note that this uses an Enum constraint and a var pattern, so will require at least C# 7.3.

public static IEnumerable<T> GetUniqueFlags<T>(this T value)
    where T : Enum
{
    var valueLong = Convert.ToUInt64(value, CultureInfo.InvariantCulture);
    foreach (var enumValue in value.GetType().GetEnumValues())
    {
        if (
            enumValue is T flag // cast enumValue to T
            && Convert.ToUInt64(flag, CultureInfo.InvariantCulture) is var bitValue // convert flag to ulong
            && (bitValue & (bitValue - 1)) == 0 // is this a single-bit value?
            && (valueLong & bitValue) != 0 // is the bit set?
           )
        {
            yield return flag;
        }
    }
}
RobinHood70
  • 123
  • 5
  • For a significant performance boost, you can cast the result of `GetEnumValues()` to `T[]` and eliminate the `enumValue is T flag` condition, but this relies on GetEnumValues always returning an array of type T, which it's not contractually required to do. – RobinHood70 Sep 06 '20 at 04:01
2

Wasn't satisfied with the answers above, although they were the start.

After piecing together some different sources here:
Previous poster in this thread's SO QnA
Code Project Enum Flags Check Post
Great Enum<T> Utility

I created this so let me know what you think.
Parameters:
bool checkZero: tells it to allow 0 as a flag value. By default input = 0 returns empty.
bool checkFlags: tells it to check whether the Enum is decorated w/ the [Flags] attribute.
PS. I don't have time right now to figure out the checkCombinators = false alg which will force it to ignore any enum values which are combinations of bits.

    public static IEnumerable<TEnum> GetFlags<TEnum>(this TEnum input, bool checkZero = false, bool checkFlags = true, bool checkCombinators = true)
    {
        Type enumType = typeof(TEnum);
        if (!enumType.IsEnum)
            yield break;

        ulong setBits = Convert.ToUInt64(input);
        // if no flags are set, return empty
        if (!checkZero && (0 == setBits))
            yield break;

        // if it's not a flag enum, return empty
        if (checkFlags && !input.GetType().IsDefined(typeof(FlagsAttribute), false))
            yield break;

        if (checkCombinators)
        {
            // check each enum value mask if it is in input bits
            foreach (TEnum value in Enum<TEnum>.GetValues())
            {
                ulong valMask = Convert.ToUInt64(value);

                if ((setBits & valMask) == valMask)
                    yield return value;
            }
        }
        else
        {
            // check each enum value mask if it is in input bits
            foreach (TEnum value in Enum <TEnum>.GetValues())
            {
                ulong valMask = Convert.ToUInt64(value);

                if ((setBits & valMask) == valMask)
                    yield return value;
            }
        }

    }

This makes use of the Helper Class Enum<T> found here that I updated to use yield return for GetValues:

public static class Enum<TEnum>
{
    public static TEnum Parse(string value)
    {
        return (TEnum)Enum.Parse(typeof(TEnum), value);
    }

    public static IEnumerable<TEnum> GetValues()   
    {
        foreach (object value in Enum.GetValues(typeof(TEnum)))
            yield return ((TEnum)value);
    }
}  

Finally, here's a example of using it:

    private List<CountType> GetCountTypes(CountType countTypes)
    {
        List<CountType> cts = new List<CountType>();

        foreach (var ct in countTypes.GetFlags())
            cts.Add(ct);

        return cts;
    }
Community
  • 1
  • 1
eudaimos
  • 655
  • 7
  • 11
  • Sorry, haven't had time to look at this project in several days. I'll get back to you once I've had a better look at your code. –  Sep 17 '11 at 03:57
  • 4
    Just a heads up that there's a bug in that code. The code in both branches of the if(checkCombinators) statement are identical. Also, perhaps not a bug, but unexpected, is that if you have an enum value declared for 0, it will always be returned in the collection. It seems that should only be returned if checkZero is true and there are no other flags set. – dhochee Jul 14 '14 at 01:39
  • @dhochee. I agree. Or the code is pretty nice, but arguments are confusing. – AFract Dec 12 '17 at 18:27
1

You can use an Iterator from the Enum. Starting from the MSDN code:

public class DaysOfTheWeek : System.Collections.IEnumerable
{
    int[] dayflag = { 1, 2, 4, 8, 16, 32, 64 };
    string[] days = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" };
    public string value { get; set; }

    public System.Collections.IEnumerator GetEnumerator()
    {
        for (int i = 0; i < days.Length; i++)
        {
            if value >> i & 1 == dayflag[i] {
                yield return days[i];
            }
        }
    }
}

It's not tested, so if I made a mistake feel free to call me out. (obviously it's not re-entrant.) You'd have to assign value beforehand, or break it out into another function that uses enum.dayflag and enum.days. You might be able to go somewhere with the outline.

SilverbackNet
  • 2,031
  • 16
  • 28
1

Here's yet another C# 7.3 solution using Linq

public static class FlagEnumExtensions
{
    public static IEnumerable<T> GetFlags<T>(this T en) where T : struct, Enum
    {
        return Enum.GetValues<T>().Where(member => en.HasFlag(member));
    }
}
PaperNick
  • 31
  • 2
0

It could be aswell as the following code:

public static string GetEnumString(MyEnum inEnumValue)
{
    StringBuilder sb = new StringBuilder();

    foreach (MyEnum e in Enum.GetValues(typeof(MyEnum )))
    {
        if ((e & inEnumValue) != 0)
        {
           sb.Append(e.ToString());
           sb.Append(", ");
        }
    }

   return sb.ToString().Trim().TrimEnd(',');
}

It goes inside if only when the enum value is contained on the value

AustinWBryan
  • 2,968
  • 3
  • 17
  • 35
G. Manucci
  • 21
  • 7
0

All the answers work well with simple flags, you're probably going to get into issues when flags are combined.

[Flags]
enum Food
{
  None=0
  Bread=1,
  Pasta=2,
  Apples=4,
  Banana=8,
  WithGluten=Bread|Pasta,
  Fruits = Apples | Banana,
}

probably need to add a check to test if the enum value it self is a combination. You'd probably need something like posted here by Henk van Boeijen to cover your requirement (you need to scroll down a bit)

Walter Vehoeven
  • 2,461
  • 14
  • 28
  • Several responses address this issue in various ways. My original intent was to only get the single-bit values, even if None/multi-bit values were present, but I neglected to specify that in the OP. – RobinHood70 Sep 06 '20 at 02:55
-1

You can do it directly by converting to int but you will loose type checking. I think the best way is use something similar to my proposition. It keep the proper type all the way. No conversion required. It is not perfect due to boxing which will add a little hit in performance.

Not perfect (boxing), but it does the job with no warning...

/// <summary>
/// Return an enumerators of input flag(s)
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static IEnumerable<T> GetFlags<T>(this T input)
{
    foreach (Enum value in Enum.GetValues(input.GetType()))
    {
        if ((int) (object) value != 0) // Just in case somebody has defined an enum with 0.
        {
            if (((Enum) (object) input).HasFlag(value))
                yield return (T) (object) value;
        }
    }
}

Usage:

    FileAttributes att = FileAttributes.Normal | FileAttributes.Compressed;
    foreach (FileAttributes fa in att.GetFlags())
    {
        ...
    }
Eric Ouellet
  • 9,516
  • 8
  • 69
  • 100