Unleashing the Power of Flags in C# and ReactJS: Why This Simple Trick Changes Everything! (#csharp #dev #flags #dotnet #enums #reactjs #javascript #typescript)

Unleashing the Power of Flags in C# and ReactJS

Overview

Ever stumbled upon [Flags] while coding in C# and thought, “Hmm, what wizardry is this?” You’re not alone! Today, let’s uncover how this attribute works, and how you can take advantage of it to improve your application.

The [Flags] attribute is a new feature that was just released in C# 10, and… Just kidding! 😂 This thing is there since version 1.0. This attribute allows an enum type to represent a combination of values. Yes, with one property, you can store multiple values. Which means that instead of having IList<UserPermission>, you can have UserPermission and store all the user’s permissions in a single variable that is converted to a very small, and memory friendly, integer. 🤯

To check and modify those values, you’ll need to use bitwise operations. But don’t worry, it sounds complicated, but isn`t.

Here’s a fun fact: this concept isn’t exclusive to C#. If you’ve ever played around with Linux file permissions—those magical numbers like 777, 644, or 755—you’re already familiar with the underlying idea!

Here’s how you could emulate Linux-style file permissions using Flags in C#:

[Flags]
enum LinuxPermission
{
    None = 0,
    Execute = 1,
    Write = 2,
    Read = 4
}

// 777 permissions would be:
var userPermissions = LinuxPermission.Read | LinuxPermission.Write | LinuxPermission.Execute;
var groupPermissions = LinuxPermission.Read | LinuxPermission.Write | LinuxPermission.Execute;
var otherPermissions = LinuxPermission.Read | LinuxPermission.Write | LinuxPermission.Execute;

Why Flags Over a List of Enums?

Imagine managing a list of enums just to represent multiple selections. You have to worry about duplicates, and ordering. When checking for a specific value, you need to iterate through the list to find it, etc. Sounds heavy, right? Using Flags simplifies this tremendously:

  • Compactness: A single integer stores multiple options. Storage-efficient!
  • Performance: Bitwise operations are lightning-fast compared to iterating through lists.
  • Clarity: Combines related options into clear, concise code.

When to Use Flags (and When Not To)

Use Flags when:

  • You need multiple, simultaneous options.
  • Performance and memory efficiency matter.
  • You want clear, expressive/readable code.

Avoid Flags when:

  • Each enum value must strictly be mutually exclusive.
  • Your enum naturally represents distinct states rather than combinable options.

Obviously, use your judgment. If you’re unsure, consider the pros and cons of each approach. However, this list is not exhaustive, or written in stone, and there are exceptions to every rule.

Practical Example / How to use it

Here’s a practical example to illustrate how Flags can simplify your code:

[Flags]
public enum PizzaToppings
{
    None = 0,
    Cheese = 1,
    Pepperoni = 2,
    Olives = 4,
    Mushrooms = 8,
    AllToppings = Cheese | Pepperoni | Olives | Mushrooms
}

class Program
{
    static void Main(string[] args)
    {
        PizzaToppings myPizza = PizzaToppings.Cheese | PizzaToppings.Pepperoni;

        Console.WriteLine($"My pizza toppings: {myPizza}");

        // Check if specific topping is selected
        bool hasOlives = myPizza.HasFlag(PizzaToppings.Olives);
        Console.WriteLine($"Does my pizza have olives? {hasOlives}");

        // Adding toppings
        myPizza |= PizzaToppings.Olives;
        Console.WriteLine($"Updated pizza toppings: {myPizza}");

        // Removing toppings
        myPizza &= ~PizzaToppings.Cheese;
        Console.WriteLine($"Final pizza toppings: {myPizza}");
    }
}

How to Use Flags in ReactJS

All we said so far is just for C#, and it great and all, but how do we use it in ReactJS? After all, it doesn’t have the actual [Flags] attribute. 🤔 That’s actually pretty straightforward.

Consider the following models in C#:

[Flags]
public enum UserPermissions
{
  Read = 1 << 0,
  Write = 1 << 1,
  DirectMessage = 1 << 2,
  CreateGroup = 1 << 3,
  InviteToGroup = 1 << 4,
  KickFromGroup = 1 << 5,
  BanFromGroup = 1 << 6,
  ModerateGroupMessages = 1 << 7,
  PromoteToAdmin = 1 << 8,
  GroupAdmin = InviteToGroup | KickFromGroup | BanFromGroup | ModerateGroupMessages,
  GroupOwner = GroupAdmin | PromoteToAdmin,
}

[Flags]
public enum UserRoles
{
  Anonymous = 1 << 0,
  PreMember = 1 << 1,
  Member = 1 << 2,
  SubscriberTier1 = 1 << 3,
  SubscriberTier2 = 1 << 4,
  SubscriberTier3 = 1 << 5,
  Admin = 1 << 6,
}

public class User
{
  public Guid Id { get; set; }
  public string Name { get; set; } = string.Empty;
  public string Email { get; set; } = string.Empty;
  public UserRoles Roles { get; set; }
  public UserPermissions Permissions { get; set; }
  public DateTime CreatedAt { get; set; }
  public DateTime UpdatedAt { get; set; }
  public DateTime LastLogin { get; set; }
}

In the code above we have a super simplistic model for a user, with roles and permissions.

Let’s say you have a ReactJS for this application. This would be the equivalent model in TypeScript:

export enum UserRoles {
    Anonymous = 1 << 0,
    PreMember = 1 << 1,
    Member = 1 << 2,
    SubscriberTier1 = 1 << 3,
    SubscriberTier2 = 1 << 4,
    SubscriberTier3 = 1 << 5,
    Admin = 1 << 6,
}

export enum UserPermissions {
    Read = 1 << 0,
    Write = 1 << 1,
    DirectMessage = 1 << 2,
    CreateGroup = 1 << 3,
    InviteToGroup = 1 << 4,
    KickFromGroup = 1 << 5,
    BanFromGroup = 1 << 6,
    ModerateGroupMessages = 1 << 7,
    PromoteToAdmin = 1 << 8,
    GroupAdmin = InviteToGroup | KickFromGroup | BanFromGroup | ModerateGroupMessages,
    GroupOwner = GroupAdmin | PromoteToAdmin,
}

export interface User {
    id: string;
    name: string;
    email: string;
    roles: UserRoles;
    permissions: UserPermissions;
    createdAt: string;
    updatedAt: string;
    lastLogin: string;
}

As you can see, the models are pretty much the same in both languages. You can copy the models from C# and paste it in Typescript.

And to do the same operations we did in C#, you can do the following:

// Check if user has a specific permission
const hasFlag = (value: number, flag: number): boolean => (value & flag) === flag;

// Example:
const user: User = {
    id: '123',
    name: 'John Doe',
    email: 'foo@bar.today',
    roles: UserRoles.Admin,
    permissions: UserPermissions.Read | UserPermissions.Write,
    createdAt: '2022-01-01',
    updatedAt: '2022-01-01',
    lastLogin: '2022-01-01',
}

//Check if user is Admin
const isAdmin = hasFlag(user.roles, UserRoles.Admin); //Will return true.

That’s it! You can now use Flags in ReactJS as well. 🎉 Of course, the example above is super simplistic, but you can expand it to your needs. If you want to play around with it, I actually created the full Backend and Frontend for this example. It’s available in this repository in my GitHub.

In that repo you’ll find:

  • A simple C# Minimal API that uses the models above, and saves the data in a SQLite database, using EFCore. Although EFCore is an absolute overkill for this, I wanted to show how this feature seamlessly integrates with EFCore.
  • A simple ReactJS frontend that uses the models above, and shows the data in a table. You’ll be able to list, add, edit, and delete users.

I recommend opening the Devtools in your browser and checking the network tab to see the requests being made and the values being sent and received in the UserPermissions and UserRoles enums.

Note about the examples

In the C# example above, I used myPizza.HasFlag(PizzaToppings.Olives); to check if myPizza has the Olives topping. The HasFlag method is a built-in method that does some validation before checking the flag, this means that this is tad slower than the bitwise operation (myPizza & PizzaToppings.Olives) == PizzaToppings.Olives. You gain a lot in terms of readability, but you lose a lot in term os performance.

Performance differences

I said quite a bit about the flags, and how they are faster than lists, but how much faster are they? Time to show some receipts.

I created a benchmark between some operations using lists and flags. The results are below: (You can find this benchmark project in the repository mentioned above)

Quick reminder: 1 Nanosecond == 0.000000001 Seconds

List Operations

MethodMeanErrorStdDevStdErrMedianMinMaxAllocated
AddUserPermission50.00 ns17.71 ns52.22 ns5.222 ns0.0000 ns0.0000 ns200.0 ns400 B
RemoveUserPermission341.24 ns17.06 ns49.48 ns5.024 ns300.0000 ns300.0000 ns400.0 ns400 B
CheckIfUserPermissionExistsUsingContains277.65 ns15.50 ns41.91 ns4.546 ns300.0000 ns200.0000 ns300.0 ns400 B
CheckIfUserPermissionExistsUsingAny1,523.47 ns50.87 ns148.39 ns14.990 ns1,500.0000 ns1,300.0000 ns1,900.0 ns440 B
CheckIfUserPermissionExistsUsingFind454.64 ns26.80 ns77.76 ns7.895 ns400.0000 ns300.0000 ns600.0 ns400 B
CheckIfUserPermissionExistsUsingFirstOrDefault1,459.02 ns31.72 ns71.59 ns9.167 ns1,500.0000 ns1,300.0000 ns1,600.0 ns440 B

As the name of the methods suggest, here’s what they’re doing:

  1. AddUserPermission: Adds a permission to a list using the Add method.
  2. RemoveUserPermission: Removes a permission from a list using the Remove method.
  3. CheckIfUserPermissionExistsUsingContains: Checks if a permission exists in a list using the Contains method.
  4. CheckIfUserPermissionExistsUsingAny: Checks if a permission exists in a list using the Any method.
  5. CheckIfUserPermissionExistsUsingFind: Checks if a permission exists in a list using the Find method.
  6. CheckIfUserPermissionExistsUsingFirstOrDefault: Checks if a permission exists in a list using the FirstOrDefault method.

From the ways for checking if a value exist inside a list, the Contains method is the fastest from the list methods. Now let’s see the results for the flags operations:

Flags Operations

MethodMeanErrorStdDevStdErrMedianMinMaxAllocated
AddUserPermission0.0000 ns0.0000 ns0.0000 ns0.0000 ns0.0000 ns0.0000 ns0.0000 ns400 B
RemoveUserPermission0.0000 ns0.0000 ns0.0000 ns0.0000 ns0.0000 ns0.0000 ns0.0000 ns400 B
CheckIfUserPermissionExistsUsingHasFlag645.1613 ns24.6623 ns69.9629 ns7.2548 ns600.0000 ns500.0000 ns800.0000 ns448 B
CheckIfUserPermissionExistsUsingBitwise34.3434 ns16.9868 ns49.8193 ns5.0070 ns0.0000 ns0.0000 ns200.0000 ns400 B
CheckIfUserPermissionExistsUsingBitwiseWrapper50.0000 ns18.9784 ns55.9581 ns5.5958 ns0.0000 ns0.0000 ns200.0000 ns400 B

The methods are:

  1. AddUserPermission: Adds a permission to a flag using the | operator.
  2. RemoveUserPermission: Removes a permission from a flag using the & operator.
  3. CheckIfUserPermissionExistsUsingHasFlag: Checks if a permission exists in a flag using the HasFlag method.
  4. CheckIfUserPermissionExistsUsingBitwise: Checks if a permission exists in a flag using the bitwise operation (Example: (myPizza & PizzaToppings.Olives) == PizzaToppings.Olives).
  5. CheckIfUserPermissionExistsUsingBitwiseWrapper: Checks if a permission exists in a flag using a wrapper function that does the bitwise operation. I added this because this is a simple way of improving readability while keeping the performance.

As you can see, the bitwise operation to check if the user has permission is the fastest. Using the native helper method HasFlag is disappointingly slow compared to the bitwise operation.

Comparing the fastest from the list operations with the fastest from the flags operations, the flags are ~8 times faster. Even using the verification with the wrapper function, the flags are still ~5 times faster. If we check the Median value for this comparison, the performance advantage for the flags is even more evident. The thing is blazing fast!

Conclusion

So, should you use it or not? Is the performance benefits alone enough? Well, it depends. The flags are great, but they reduce the readability of the code. At a glance, the values would be a random integer, and this can be confusing if you want to query them in a database.

You could craft the flags in your system in a way that the numbers will be more meaningful, like UserPermissions = 4 means that the user can Read and Write, and if it’s equal to 777, means that the user is an Admin or something like that. There are ways to mitigate the readability issue, but it’s something to consider well before implementing it.

If in your system you have a property that can contain multiple values at once, and you need to direct the flow of the code depending on those values, and it’s all about performance, then Flags are probably the way to go. Remember: Human readability is nice, and convenient for the developer while debugging, but you should be careful when choosing to sacrifice system simplicity and performance just so it’s more convenient for you to write a SQL query in the (hopefully) rare occasions when you need to check the database directly.

Let’s say you’re processing live credit card payments, and before going throw with each transaction, you need to check the benefits of the card, so the code knows what to do with the transaction. In this case, since every millisecond counts, flags might be a great choice.

On the other hand, even if performance is important, if you have an API and it’s not a high-frequency one (like thousands of requests per second), it’s possible that the performance benefits of the flags might not make much of a difference.

Hope that helps!

References:

Translations: