C# Enum Flags Attribute Use

Good article on enum flags for C# 

You want to use enum flags to assign and check multiple constant values, and switch on these enums. Enum flags are a powerful but limited way to deal with combinations of enums. In this article, we process enum flags with bitwise operators, and then switch on those flags, using the C# language.

Using enum flags

The [Flags] attribute on an enum allows you to assign multiple values to your enum at once. You can do this with bitwise manipulations, meaning you can store an enum with A and C set, not just A and not just C. This approach has benefits in some cases, but also problems.

~~~ Program that uses [Flags] (C#) ~~~

using System;

class Program
{
    [Flags]
    enum RenderType
    {
        None = 0x0,
        DataUri = 0x1,
        GZip = 0x2,
        ContentPage = 0x4,
        ViewPage = 0x8,
        HomePage = 0x10 // Next two values could be 0x20, 0x40
    }

    static void Main()
    {
        // 1.
        // Set the first type.
        RenderType type1 = RenderType.ContentPage;

        // 2.
        // Set the second type if the condition matches.
        if (true)
        {
            type1 |= RenderType.GZip;
        }

        // 3.
        // Check the enum flags.
        Check(type1);

        // 4.
        // Set a new enum in three statements.
        RenderType type2 = RenderType.ViewPage;
        type2 |= RenderType.DataUri;
        type2 |= RenderType.GZip;

        // 5.
        // See if the enum contains this flag.
        if ((type2 & RenderType.DataUri) == RenderType.DataUri)
        {
            Console.WriteLine("True");
        }

        // 6.
        // See if the enum contains this flag.
        if ((type2 & RenderType.ContentPage) == RenderType.ContentPage)
        {
            throw new Exception();
        }

        // 7.
        // Check the enum flags.
        Check(type2);
    }

    static void Check(RenderType type)
    {
        // Switch on the flags.
        switch (type)
        {
            case RenderType.ContentPage | RenderType.DataUri | RenderType.GZip:
                {
                    Console.WriteLine("content, datauri, gzip");
                    break;
                }
            case RenderType.ContentPage | RenderType.GZip: // < first match
                {
                    Console.WriteLine("content, gzip");
                    break;
                }
            case RenderType.ContentPage:
                {
                    Console.WriteLine("content");
                    break;
                }
            case RenderType.ViewPage | RenderType.DataUri | RenderType.GZip: // < second match
                {
                    Console.WriteLine("view, datauri, gzip");
                    break;
                }
            case RenderType.ViewPage | RenderType.GZip:
                {
                    Console.WriteLine("view, gzip");
                    break;
                }
            case RenderType.ViewPage:
                {
                    Console.WriteLine("view");
                    break;
                }
            case RenderType.HomePage | RenderType.DataUri | RenderType.GZip:
                {
                    Console.WriteLine("home, datauri, gzip");
                    break;
                }
            case RenderType.HomePage | RenderType.GZip:
                {
                    Console.WriteLine("home, gzip");
                    break;
                }
            case RenderType.HomePage:
                {
                    Console.WriteLine("home");
                    break;
                }
        }
    }
}

~~~ Output of the program ~~~ content, gzip True view, datauri, gzip

Overview of the example. This example shows an enum with six bit flags in it. Note how the word [Flags] appears on top of the enum, with the square brackets. This is an attribute that tells .NET to allow you to assign the enum with bitwise operators.

Attribute Tips and Examples

Description of the enum values. The values 0x0, 0x1, 0x2, 0x4 and so on indicate powers of two. In computer bits, powers of two contain one bit set, moving from the first bit to the final bit. You could use the decimal values, 0, 1, 2, 4, 8… instead.

Description of Main entry point. The Main method here has several example steps. First it declares a new RenderType enum and assigns the RenderType.ContentPage value. This is the same as you would use a normal enum.

Setting an enum flag. The |= operator next actually adds a flag to the enum, so the enum now contains two flag bits. You can use |= to add bits, while & will test bits without setting them.

Description of switch method. The method Check is the final part of the example. It shows how you can switch on enum flags. This is very useful because it allows you to act on combinations of the flags in a constant-time expression. The switch statement here is faster than other constructs. Note how the | operator is used in the cases; this simply means the values are combined.

Steps 5 and 6. These two steps show how you can test your enum with flags using the & bitwise AND operator. You have to check the result of & with the actual enum flag again.

Understanding bitwise AND, bitwise OR

Bitwise AND, which you use with &, returns a value with 1 in the targeted bit if both values contain the bit. Therefore, you can AND two values together and test the result for the target bit. Bitwise OR, which you use with |, returns 1 in the bit if either value has it set. This means it can be used in the switch, setting all bits in the | expressions.

Binary Representation for Integer

Benefits of switch on enum flags

When you are using enum flags, you are concerned about performance. The switch compiles to a jump table which is lots faster than if/else chains. I could not find other examples on the Internet that use the flags in a switch.

Switch Enum

Limitations

Unfortunately, using bitwise flags on your enum has severe limitations. It can help improve certain code that has few flags that are often combined. However, you cannot extend your enum flags nearly as much as a regular enum. Therefore, if you need 100 enum values, or may need that many in the future, you should use separate integer enums.

Summary

Enum flags are a versatile and powerful way to represent more complex constants and combinations. Here we saw how you can use bitwise flags with your enums in the C# language. The example shows how you can assign, add, set, check, and switch on your enum with the [Flags] attribute. We also looked at the flaws in this approach and how it can limit the development of your code.

Enum Overview

Attribute Overview