Search code examples
c#genericsenumsenum-flags

How to generically combine all bits (I mean OR all values) of a [FLAGS] enum, having only valid values (bits) declared in the resulting enum?


How to generically combine all bits (I mean OR all values) of a [FLAGS] enum, having only valid values (bits) declared in the enum?

Ex: [Flags] enum SuitsFlags { Spades = 1, Clubs = 2, Diamonds = 4, Hearts = 8 } => Expected solution would: return Spades | Clubs | Diamonds | Hearts; but using a generic function.

I try to ask the question previously but I asked the wrong question: Enum fun... Why these 2 errors.... My question was closed but peoples gave me some great clues on how to do it. I finally did it with pretty much works (trial and errors). So I wanted to leave a trace of my solution to help others, and potentially have better solution from other users too.

It is not the first time I need that. Although anybody can do it quickly by OR (val1 | val2 | ...) each values manually, that could lead to runtime error when a new enum value is added and the programmer forget to verify each and every places where the enum is used.


Solution

  • This is my second answer which I prefer because of its advantages:

    • It has no unsafe code.
    • It does not require compilation.
    • It's probably faster on first call than any code requiring compilation
    • It should also be the fastest on subsequent calls, due to the caching

    Usage sample:

    private ItemCategory _categoryFilter = EnumFlagsAll<ItemCategory>.Value;
    

    Code:

    public static class EnumFlagsAll<T> where T : struct, Enum
        {
            // **************************************************************
            static EnumFlagsAll()
            {
                T res = default;
                foreach (T val in Enum.GetValues<T>())
                {
                    res = (T)GenericAddBits(res, val);
                }
                Value = res;
            }
    
            public static T Value { get; }
    
            // **************************************************************
            /// <summary>
            /// Generic method to add bit(s) from the first value. Will perform an OR.
            /// </summary>
            /// <param name="val"></param>
            /// <param name="bitsToAdd"></param>
            /// <returns></returns>
            public static Enum GenericAddBits(Enum val, Enum bitsToAdd)
            {
                // consider adding argument validation here
    
                return (Enum)Enum.ToObject(val.GetType(), Convert.ToUInt64(val) | Convert.ToUInt64(bitsToAdd));
            }
    
            // **************************************************************
        }