C-Sharp | Java | Python | Swift | GO | WPF | Ruby | Scala | F# | JavaScript | SQL | PHP | Angular | HTML
An enum type with the [Flags] attribute can have multiple constant values assigned to it. And it is still possible to test for these values in switches and if-statements.
Example. 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.
Note: This approach has benefits in some cases, but also problems. This next program uses enum Flags in many ways.
C# program that uses Flags 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 content, gzip True view, datauri, gzip
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.
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.
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.
Next: The "|=" operator actually adds a flag to the enum, so the enum now contains two flag bits.
Also: You can use "|=" to add bits, while & will test bits without setting them.
Switch. The method Check is the final part of the example. It shows how to switch on enum flags. This is useful—it allows you to act on combinations of the flags in a constant-time expression.
Note: The "|" operator is used in the cases. This simply means the values are combined.
Bitwise AND, OR. Bitwise AND, which you use with &, returns a value with 1 in the targeted bit if both values contain the bit. You can therefore 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. Examples are shown in the above program.
Binary Representation for IntegerAnd Bitwise OperatorBitwise Or
Discussion. 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 that use the flags in a switch.
Also, using bitwise flags on your enum has severe limitations. It can help improve certain code that has few flags that are often combined. But 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 represent more complex constants and combinations. We used bitwise flags with enums in the C# language. The example shows how to assign, add, set, check, and switch on an enum with the [Flags] attribute.
Also: We looked at the flaws in this approach and how it can limit the development of your code.