Flags
, enum
In C#, Flags
allow an enum
value to contain many values. An enum
type with the Flags
attribute can have multiple constant values assigned to it.
With Flags
, it is still possible to test enums in switches and if
-statements. Flags
can be removed or added. We can specify multiple flags with the "or" operator. The HasFlag()
method is helpful.
This program introduces a FileAttributes
enum
. We use the values 0, 1, 2, 4 to indicate the underlying bits for each value—we should double
each value to avoid conflicts.
FileAttributes
enum
.HasFlag()
method, we determine if a flag is set. This method is the clearest way to test for a flag.HasFlag()
and test it for false.enum
value. We use AND and the bitwise complement.enum
value again to determine whether we correctly removed the flag from it.using System; class Program { [Flags] enum FileAttributes { None = 0, Cached = 1, Current = 2, Obsolete = 4, } static void Main() { // Part 1: create new enum instance with flags. Console.WriteLine("SET CACHED AND CURRENT FLAGS"); var attributes = FileAttributes.Cached | FileAttributes.Current; // Part 2: see if current flag is set. if (attributes.HasFlag(FileAttributes.Current)) { Console.WriteLine("File is current"); } // Part 3: see if obsolete flag is not set. if (!attributes.HasFlag(FileAttributes.Obsolete)) { Console.WriteLine("File is not obsolete"); } // Part 4: remove current flag. Console.WriteLine("REMOVE CURRENT FLAG"); attributes &= ~FileAttributes.Current; // Part 5: see if current flag is set again. if (!attributes.HasFlag(FileAttributes.Current)) { Console.WriteLine("File is not current"); } } }SET CACHED AND CURRENT FLAGS File is current File is not obsolete REMOVE CURRENT FLAG File is not current
Flags
This example shows an enum
with 6 bit flags in it. Notice how the word [Flags
] appears on top of the enum
, with the square brackets.
switch
on enum
flags. We act on combinations of the flags in a constant-time expression.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() { // Set the first type. RenderType type1 = RenderType.ContentPage; // Set the second type if the condition matches. if (true) { type1 |= RenderType.GZip; } // Check the enum flags. Check(type1); // Set a new enum in three statements. RenderType type2 = RenderType.ViewPage; type2 |= RenderType.DataUri; type2 |= RenderType.GZip; // See if the enum contains this flag. if ((type2 & RenderType.DataUri) == RenderType.DataUri) { Console.WriteLine("True"); } // See if the enum contains this flag. if ((type2 & RenderType.ContentPage) == RenderType.ContentPage) { throw new Exception(); } // 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; } } } }content, gzip True view, datauri, gzip
The "|=" operator actually adds a flag to the enum
, so the enum
now contains two flag bits. You can use "|=" to add bits, while "and" will test bits without setting them.
switch
, setting all bits in the cases.When you are using enum
flags, you are concerned about performance. The switch
compiles to a jump table which is faster than if-else
chains.
Enum
flags represent more complex constants and combinations. We used HasFlag()
and bitwise flags with enums. We can assign, add, set, check, and switch
on flags.