1

Suppose I have the following:

[Flags]
public enum Options : long
{
    None = 0,

    Flag1 = 0x00000001,
    Flag2 = 0x00000002,
    Flag3 = 0x00000004,
    Flag4 = 0x00000008,
    Flag5 = 0x00000010,
    // ...
    FlagV = 0x10000000000,
    FlagW = 0x20000000000,
    FlagX = 0x40000000000,
    FlagY = 0x80000000000,
    FlagZ = 0x100000000000
}

Currently, to determine if a flag is set, I am doing this:

(myOptions & (long)Options.Flag1) == (long)Options.Flag1

How do I determine whether ANY flag above FlagV (e.g. FlagW, FlagX, etc.) is set and retrieve its value (e.g. if FlagW, FlagX, and FlagZ are set, I want to retrieve the value of FlagW)? In other words, is there an alternative to this:

if ((myOptions & (long)Options.FlagW) == (long)Options.FlagW)
    return (long)Options.FlagW;
else if ((myOptions & (long)Options.FlagX) == (long)Options.FlagX)
    return (long)Options.FlagX;
else if ((myOptions & (long)Options.FlagY) == (long)Options.FlagY)
    return (long)Options.FlagY;
// etc.
arao6
  • 3,316
  • 5
  • 30
  • 51
  • 1
    To check if *any* of the flags is set, use `myOptions != 0`. To retrieve its value, simply bitwise-AND (`&`) it with the flag itself. – The Paramagnetic Croissant Aug 31 '14 at 18:08
  • Sorry. Edited my question for more clarity. Basically, I am trying to determine whether any flag above FlagV is set, and if any is, what that flag is. – arao6 Aug 31 '14 at 18:15
  • @arao6 Your last code snippet is equivalent with `return myOptions;`. – The Paramagnetic Croissant Aug 31 '14 at 18:18
  • Basically, after clearing all the flags you don't care about, you're left looking for the least significant bit that's set. [Here are some C++ answers to that question](http://stackoverflow.com/questions/757059/position-of-least-significant-bit-that-is-set), some of which should be easily adaptable to C#. –  Aug 31 '14 at 18:29
  • BTW, the answer to the question you seem to ask (but not what you actually want, based on the rest of your question) is simpler: determining if any flag is set out of `W`, `X`, `Y` is simply `myOptions & (Options.W | Options.X | Options.Y) != 0` (with casts as necessary depending on the type of `myOptions`). –  Aug 31 '14 at 18:30

4 Answers4

3

You can iterate through all Options values.

var currentVal = Options.FlagV | Options.FlagW;
     foreach (Options enumVal in Enum.GetValues(typeof(Options)))
         if (enumVal > Options.FlagV && (enumVal & currentVal) == enumVal)
                //Do stuff
brz
  • 5,926
  • 1
  • 18
  • 18
2

This will give you a list of flags set in myOptions:

var flags = Enum.GetValues(typeof(Options))
                .Where(f => myOptions.HasFlag(f))
                .ToList();

EDIT: it looks like your myOptions is actually a long, otherwise your code wouldn't have compiled since you can't apply & to an enum and a long. So try this instead:

var enumVal = (Options)myOption;
var flags = Enum.GetValues(typeof(Options))
                .Where(f => enumVal.HasFlag(f))
                .ToList();
Eren Ersönmez
  • 38,383
  • 7
  • 71
  • 92
1

First, you might want to reconsider the design which led you to more than 32 flags, as that sounds troublesome in its own right.

Beyond that, consider that you are only doing bit arithmetic, so something like the following is both efficient (compiles to a couple instructions), and easy to maintain:

public enum Options : long
{
    FlagA = 0x00000001,
    // ...
    FlagZ = 0x80000000,
    // ...
    HighFlags = 0xffff0000,
    LowFlags  = 0x0000ffff
}

Then you can check for any HighFlags by doing (options & Options.HighFlags) != 0 and get only HighFlags with options & Options.HighFlags.

If you cannot modify the enum, or don't want to rely upon specific values, you could also or the values together at runtime:

public static class OptionsHelper
{
    private readonly static Options HighFlags = Options.FlagM 
        | Options.FlagN
        // ...
        | Options.FlagZ;

    public static bool HasHighFlags(this Options opt)
    {
        return (opt & HighFlags) != 0;
    }

    public static Options GetHighFlags(this Options opt)
    {
        return (opt & HighFlags);
    }

    public static IEnumerable<Options> GetSetHighFlags(this Options opt)
    {
        var highFlags = GetHighFlags(opt);

        if (highFlags != 0)
        {
            for (ulong cFlag = 1; cFlag != 0; cFlag <<= 1)
            {
                if ((highFlags & cFlag) != 0)
                {
                    yield return (Options)cFlag;
                }
            }
        }
    }
}

Used as an extension method (options.HasHighFlags()) or options.GetSetHighFlags().First().

Mitch
  • 21,223
  • 6
  • 63
  • 86
  • Sure: it doesn't answer the question. It only tells you whether any of the high flags have been set, but not the value of one of those flags, and the question specifically asks for that too. –  Aug 31 '14 at 18:38
  • No, when the caller passes `Options.FlagW | Options.FlagZ`, the OP wants to return `Options.FlagW`, according to what's in the question. You would return `Options.FlagW | Options.FlagZ`. –  Aug 31 '14 at 18:40
  • I like your edit here. There's two minor errors: the C# syntax is `ulong`, not `unsigned long`. And your `for` loop won't ever enter the body with `cFlag` equal to `(1UL << 63)`. But you can solve that by changing the loop condition to `cFlag != 0` (which works even in `checked` context). –  Aug 31 '14 at 20:50
0

You can simply do something like this:

if (optons & 0xfe0000000000) // Typecasts will be needed
    // One of those flags is set.

Also, note that newer versions of .NET support the options.HasFlag() method, which simplifies determining whether or not a flag is defined.

In fact, I didn't test it but you should be able to do something like this:

if (optons.HasFlag(0xfe0000000000)) // Typecasts will be needed
    // One of those flags is set.
Jonathan Wood
  • 65,341
  • 71
  • 269
  • 466