C# Foundations · Lesson 32

Flags enums and independent capabilities

Represent combinations of small, independent options with bits.

How it works

An enum normally gives names to a set of integral constants. A flags enum uses distinct powers of two so that several independent choices can be combined in one value. Bitwise OR adds named capabilities to a combination, and bitwise AND tests which bits are present. A zero value often represents no capabilities at all.

This representation fits independent options such as read and write permission. It is less suitable for mutually exclusive states such as pending and complete, where combining two states should not be meaningful. The Flags attribute helps formatting communicate combinations, but it does not prevent invalid numeric combinations or enforce an application's authorization rules by itself.

Walk through the example. The example combines Read and Write, then checks for Read with an AND comparison. It checks Execute with HasFlag, which is false because the execute bit is absent. Removing Write uses AND with the complemented bit mask. The final comparison confirms that only Read remains. Every operation changes a value, rather than mutating the enum definition.

Watch the boundary. Give the basic flags nonoverlapping values such as one, two, four, and eight. Sequential values such as one, two, and three would make the third named option overlap the first two. Be careful when testing the zero flag: every value contains zero bits, so HasFlag with a zero argument returns true. Validate unknown bits when accepting numeric input from outside the program.

Practice independently. Define flags for three report sections, combine two of them, and print which sections will be included. Add an explicit None member and a named combination of all supported flags. Test a numeric value containing an unknown bit and reject it with a mask check. Finally describe a workflow state that should use an ordinary enum instead, and explain why combining its values would be misleading.

A working example

using System;
using System.Collections.Generic;
using System.Linq;
using System.Globalization;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;

Access permissions = Access.Read | Access.Write;
Console.WriteLine((permissions & Access.Read) == Access.Read);
Console.WriteLine(permissions.HasFlag(Access.Execute));
permissions &= ~Access.Write;
Console.WriteLine(permissions == Access.Read);
[Flags]
enum Access { None = 0, Read = 1, Write = 2, Execute = 4 }

Expected output

True
False
True
Try this
Use powers of two for independent flags, and validate unknown bits at input boundaries.