简体   繁体   中英

Determining if any flag is set over a certain value

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 (eg FlagW, FlagX, etc.) is set and retrieve its value (eg 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.

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

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();

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() .

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM