InfiniteEnumFlags 0.5.0
See the version list below for details.
dotnet add package InfiniteEnumFlags --version 0.5.0
NuGet\Install-Package InfiniteEnumFlags -Version 0.5.0
<PackageReference Include="InfiniteEnumFlags" Version="0.5.0" />
<PackageVersion Include="InfiniteEnumFlags" Version="0.5.0" />
<PackageReference Include="InfiniteEnumFlags" />
paket add InfiniteEnumFlags --version 0.5.0
#r "nuget: InfiniteEnumFlags, 0.5.0"
#:package InfiniteEnumFlags@0.5.0
#addin nuget:?package=InfiniteEnumFlags&version=0.5.0
#tool nuget:?package=InfiniteEnumFlags&version=0.5.0
InfiniteEnumFlags
InfiniteEnumFlags gives you [Flags]-style behavior without the 32-bit or 64-bit limit of built-in .NET enums.
Use it when native C# flags are the right model, but int, long, or ulong are too small. This is common for permissions, feature switches, policy rules, and other systems where the list can grow past 64 values.
You still get named values, bitwise operators, and compact storage, but the flags are backed by a growable bit array instead of a fixed-size numeric enum.
Install
dotnet add package InfiniteEnumFlags
Define flags
Create a class that inherits from InfiniteEnum<T> and expose each value as a static Flag<T>.
-1 is reserved for None. Every other number is the zero-based bit index.
using InfiniteEnumFlags;
public sealed class Permissions : InfiniteEnum<Permissions>
{
public static readonly Flag<Permissions> None = new(-1); // 0 -> 0
public static readonly Flag<Permissions> ReadUsers = new(0); // 1 -> 1
public static readonly Flag<Permissions> CreateUsers = new(1); // 2 -> 10
public static readonly Flag<Permissions> DeleteUsers = new(2); // 4 -> 100
public static readonly Flag<Permissions> ViewReports = new(100);
}
The constructor value is the bit index, not the decimal value. For example, new(2) means "turn on bit 2", which is the same idea as 1 << 2.
| Flag | Index | Decimal value | Binary shape |
|---|---|---|---|
None |
-1 |
0 |
0 |
ReadUsers |
0 |
1 |
1 |
CreateUsers |
1 |
2 |
10 |
DeleteUsers |
2 |
4 |
100 |
ViewReports |
100 |
very large | bit 100 is on |
Native [Flags] enums store this shape inside an int, long, or ulong. InfiniteEnumFlags stores the same shape in a growable bit array, so high indexes like 100, 500, or 10_000 are still valid.
Combine and check flags
You can use familiar bitwise operators.
var permissions = Permissions.ReadUsers | Permissions.CreateUsers;
// binary: 1 | 10 = 11
bool canRead = permissions.HasFlag(Permissions.ReadUsers); // true
bool canDelete = permissions.HasFlag(Permissions.DeleteUsers); // false
Supported operators:
| Operator | Meaning | Example |
|---|---|---|
| |
add/combine flags | ReadUsers | CreateUsers |
& |
keep only shared flags | permissions & required |
^ |
toggle flags | permissions ^ DeleteUsers |
~ |
invert known bits in the current value length | ~permissions |
The helper methods mirror the common operators:
| Method | Operator | Meaning |
|---|---|---|
SetFlag |
| |
add flags |
UnsetFlag |
& ~ |
remove flags |
ToggleFlag |
^ |
toggle flags |
HasFlag checks for any overlap. This is the default because most permission-style checks ask: "does this value contain at least one of these flags?"
var required = Permissions.ReadUsers | Permissions.CreateUsers;
permissions.HasFlag(required); // true
Permissions.ReadUsers.HasFlag(required); // true
Use HasAllFlags when every requested flag must be present:
permissions.HasAllFlags(required); // true
Permissions.ReadUsers.HasAllFlags(required); // false
Set, unset, and toggle
var permissions = Permissions.None
.SetFlag(Permissions.ReadUsers, Permissions.ViewReports);
permissions = permissions.UnsetFlag(Permissions.ViewReports);
permissions = permissions.ToggleFlag(Permissions.DeleteUsers);
Work with names
InfiniteEnum<T> can read the static flag fields you define.
var names = Permissions.GetNames().ToList();
// None, ReadUsers, CreateUsers, DeleteUsers, ViewReports
var selectedNames = Permissions.GetNames(
Permissions.ReadUsers | Permissions.DeleteUsers);
// ReadUsers, DeleteUsers
var read = Permissions.FromName("ReadUsers");
var combined = Permissions.FromNames("ReadUsers", "ViewReports");
if (Permissions.TryFromName("DeleteUsers", out var deleteUsers))
{
// use deleteUsers
}
All returns all non-empty flags:
var allPermissions = Permissions.All;
Store and restore values
Use ToId when you need a compact string value for storage.
IDs are canonical: equal flags produce the same ID even if they were created with different internal bit lengths. The format is normalized bytes encoded as unpadded base64url, with "0" reserved for None.
var permissions = Permissions.ReadUsers | Permissions.ViewReports;
string id = permissions.ToId();
var restored = Permissions.FromId(id);
Console.WriteLine(permissions == restored); // true
Small values stay small:
| Value | ID |
|---|---|
None |
0 |
ReadUsers |
AQ |
CreateUsers |
Ag |
ReadUsers | CreateUsers |
Aw |
DeleteUsers |
BA |
For plain padded base64 storage, use ToBase64String, ToBase64Trimmed, and FromBase64.
Scoped IDs
ToId stores only the flag value. That keeps IDs tiny and close to native enum behavior.
If values from different enum classes may share the same database column, queue, or API field, use scoped IDs:
string id = permissions.ToScopedId();
var restored = Permissions.FromScopedId(id);
The default scope is the enum class name. You can override it when multiple enum classes should intentionally share the same ID space:
string id = permissions.ToScopedId("permissions-v1");
var restored = Permissions.FromScopedId(id, "permissions-v1");
Scoped IDs are still compact, but they are not just a visible prefix. The scope changes the encoded value, so the raw value ID is not exposed inside the scoped ID.
Notes
Flag<T>values are immutable from public APIs.- Equality ignores trailing zero bits, so the same logical flags compare equal even if they were created with different internal lengths.
Noneis an empty flag set.HasFlag(None)returnsfalsebecause there are no bits to overlap.HasAllFlags(None)returnstrue, because an empty requirement is always satisfied.
License
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 is compatible. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.1 is compatible. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.1
- No dependencies.
-
net10.0
- No dependencies.
-
net6.0
- No dependencies.
-
net7.0
- No dependencies.
-
net8.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories (1)
Showing the top 1 popular GitHub repositories that depend on InfiniteEnumFlags:
| Repository | Stars |
|---|---|
|
youssefbennour/AspNetCore.Starter
A modular-monolith ASP.NET Core starter inspired by Evolutionary-architecture
|
| Version | Downloads | Last Updated | |
|---|---|---|---|
| 0.6.0 | 85 | 5/5/2026 | |
| 0.5.0 | 100 | 5/4/2026 | |
| 0.4.3 | 60,725 | 11/30/2023 | |
| 0.4.2 | 4,346 | 3/17/2023 | |
| 0.4.1 | 1,207 | 12/16/2022 | |
| 0.4.0 | 511 | 12/2/2022 | |
| 0.3.0 | 559 | 11/8/2022 | |
| 0.2.1 | 491 | 11/7/2022 | |
| 0.2.0 | 1,346 | 11/7/2022 | |
| 0.1.2 | 643 | 10/26/2022 | |
| 0.1.1 | 620 | 10/26/2022 | |
| 0.1.0 | 641 | 10/25/2022 | |
| 0.0.4 | 636 | 10/25/2022 | |
| 0.0.3 | 636 | 10/24/2022 |