Mastering the [Flags] Attribute in C#: Creating Powerful Bitwise Enums

Morteza JangjooMorteza Jangjoo
3 min read

When working with enums in C#, we usually think of them as a list of distinct values. However, there are situations where a variable should represent a combination of multiple enum values at the same time — for example, user permissions, file access modes, or UI display options.

That’s where the [Flags] attribute comes in.


What is [Flags] in C#?

The [Flags] attribute is applied to an enum to indicate that it should be treated as a bit field — a set of flags that can be combined using bitwise operations.

A regular enum variable can only hold one value at a time, but a [Flags] enum can store multiple active values in a single variable.


Defining a [Flags] Enum

When defining a flags enum, each value should be a power of 2:

[Flags]
public enum FileAccess
{
    None = 0,
    Read = 1,       // 0001
    Write = 2,      // 0010
    Execute = 4,    // 0100
    ReadWrite = Read | Write, // 0011
    All = Read | Write | Execute // 0111
}

Combining Flags

You can combine multiple flags using the bitwise OR (|) operator:

FileAccess access = FileAccess.Read | FileAccess.Write;
Console.WriteLine(access); 
// Output: Read, Write

Checking for a Flag

To see if a flag is set, use the bitwise AND (&) operator:

bool canRead = (access & FileAccess.Read) == FileAccess.Read; // true
bool canExec = (access & FileAccess.Execute) == FileAccess.Execute; // false

Why Use [Flags] Instead of a Regular Enum?

Without [Flags], the combination logic still works, but the ToString() output will show the raw number instead of meaningful flag names:

Console.WriteLine(access);
// Without [Flags]: 3
// With [Flags]: Read, Write

Real-World Example: User Permissions

A common use case for [Flags] is managing user permissions in an application.

[Flags]
public enum UserPermissions
{
    None = 0,
    ViewDashboard = 1,
    EditUsers = 2,
    ManageProducts = 4,
    AccessReports = 8,
    All = ViewDashboard | EditUsers | ManageProducts | AccessReports
}

Assigning Permissions:

UserPermissions admin = UserPermissions.ViewDashboard | UserPermissions.EditUsers | UserPermissions.AccessReports;
Console.WriteLine(admin);  
// Output: ViewDashboard, EditUsers, AccessReports

Checking Permissions:

bool canEdit = (admin & UserPermissions.EditUsers) == UserPermissions.EditUsers; // true
bool canManageProducts = (admin & UserPermissions.ManageProducts) == UserPermissions.ManageProducts; // false

Filtering Users by Permission:

var users = new List<(string Name, UserPermissions Permissions)>
{
    ("Ali", UserPermissions.ViewDashboard | UserPermissions.AccessReports),
    ("Sara", UserPermissions.ViewDashboard | UserPermissions.EditUsers),
    ("Reza", UserPermissions.All)
};

var reportUsers = users.Where(u => (u.Permissions & UserPermissions.AccessReports) == UserPermissions.AccessReports);

foreach (var user in reportUsers)
{
    Console.WriteLine(user.Name); // Ali, Reza
}

Best Practices for [Flags]

  1. Use powers of 2 for each flag (1, 2, 4, 8, 16…).

  2. Define a None = 0 value.

  3. Avoid overlapping bit values.

  4. Use [Flags] only when multiple values may be combined.


Conclusion

The [Flags] attribute in C# is a powerful tool for representing multiple options in a single variable. It improves readability, saves storage, and makes your code cleaner when dealing with combinations of states or permissions.


💡 Pro Tip: You can store [Flags] enums directly in a database as integers, making them both efficient and easy to query.


I’m Morteza Jangjoo and “Explaining things I wish someone had explained to me”

#dotnet #csharp #enums #flags #programmingtips

0
Subscribe to my newsletter

Read articles from Morteza Jangjoo directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Morteza Jangjoo
Morteza Jangjoo