Search code examples
c#mathenums

C#: Best way to check against a set of Enum Values?


suppose you have enum MyEnum {A = 0, B = 1, C = 2, D = 4, E = 8, F = 16};

At some point you have a function that will check an instance of MyEnum and return true if it is C,D, or F

bool IsCDF(MyEnum enumValue) 
{
  return //something slick
}

I remember that there was some really slick way to do bit shifting and preform this operation that read way better than a bunch of ternary if statements but for the life of me I can't remember what it is.

Anyone know?


Solution

  • If you make it a [Flags] enum, you can assign a different bit value (1, 2, 4, 8, 16...) to each enumerated value. Then you can use a bitwise operation to determine if a value is one of a set of possible values.

    So, to see if it is C, D, or F:

    bool IsCDF(MyEnum enumValue)
    {
        return ((enumValue & (MyEnum.C | MyEnum.D | MyEnum.F)) != 0);
    }
    

    or using HasFlag() (less efficient but more readable):

    bool IsCDF(MyEnum enumValue)
    {
        return enumValue.HasFlag(MyEnum.C | MyEnum.D | MyEnum.F);
    }
    

    Note that this will not work for a value of 0 (in your example, 'A'), and you must be careful that all enum values resolve to unique bit values (i.e. non-zero powers of two).

    The advantages of this approach are:

    • it will typically take a single CPU instruction/cycle to execute, whereas doing three separate "if" checks will take 3 or more instructions (depending on your target platform).
    • You can pass the set of values that you want to test with as an enum value (a single integer) instead of needing to use lists of enum values.
    • You can do lots of other useful things with bitwise operations, which would be clunky and slow with ordinary numerical/comparative approaches.

    Handy hint: When defining [Flags] enums, use left-shift (<<) to make the bit values clearer (and much harder to get wrong) especially for higher-order bits:

    [Flags]
    enum MyEnum
    {
        A = 1 << 0,     // Equivalent to 1
        B = 1 << 1,     // Equivalent to 2
        C = 1 << 2,     // Equivalent to 4
        D = 1 << 3,     // Equivalent to 8
        …
        Big = 1 << 26,  // Equivalent to 67108864
    }