Skip to main content

LayeredCraft.OptimizedEnums by LayeredCraft

NuGet / site data

Nuget GitHub last commit GitHub Repo stars

Details

Info

info

Name: LayeredCraft.OptimizedEnums

High-performance alternative to SmartEnum using source generation. Provides zero-reflection, AOT-safe enum types with compile-time validation and O(1) lookup tables.

Author: LayeredCraft

NuGet: https://www.nuget.org/packages/LayeredCraft.OptimizedEnums/

You can find more details at https://github.com/layeredcraft/optimized-enums

Source: https://github.com/layeredcraft/optimized-enums

Author

note

LayeredCraft Alt text

Original Readme

note

LayeredCraft.OptimizedEnums

LayeredCraft.OptimizedEnums is a modular C# .NET library providing high-performance, AOT-safe smart enum patterns using source generation. Inherit from a base class and the generator produces O(1) lookup tables, collection properties, and factory methods — all at compile time with zero reflection at runtime.

Key Features
  • Zero reflection — all lookup tables are source-generated at compile time
  • AOT / trimming friendly — compatible with NativeAOT, ReadyToRun, and Blazor WASM
  • O(1) lookupsFromName, FromValue, ContainsName, ContainsValue
  • Compile-time validation — errors for missing partial, duplicate values/names
  • No allocations per call — all collections are statically cached
  • Inheritance-based triggering — no attribute required, just inherit and go
📦 Packages
PackageNuGetDownloads
LayeredCraft.OptimizedEnumsNuGetDownloads
LayeredCraft.OptimizedEnums.SystemTextJsonNuGetDownloads
LayeredCraft.OptimizedEnums.EFCoreNuGetDownloads
LayeredCraft.OptimizedEnums.Dappercoming soon
LayeredCraft.OptimizedEnums.AutoFixturecoming soon

Build Status

Usage
public sealed partial class OrderStatus : OptimizedEnum<OrderStatus, int>
{
public static readonly OrderStatus Pending = new(1, nameof(Pending));
public static readonly OrderStatus Paid = new(2, nameof(Paid));
public static readonly OrderStatus Shipped = new(3, nameof(Shipped));

private OrderStatus(int value, string name) : base(value, name) \{ }
}

Or use the int-defaulting convenience base class:

public sealed partial class Priority : OptimizedEnum<Priority>
{
public static readonly Priority Low = new(1, nameof(Low));
public static readonly Priority Medium = new(2, nameof(Medium));
public static readonly Priority High = new(3, nameof(High));

private Priority(int value, string name) : base(value, name) \{ }
}

The source generator produces:

// Lookup
var status = OrderStatus.FromName("Paid"); // OrderStatus.Paid
var status = OrderStatus.FromValue(3); // OrderStatus.Shipped

// Try-style
OrderStatus.TryFromName("Paid", out var result);
OrderStatus.TryFromValue(3, out var result);

// Membership
OrderStatus.ContainsName("Paid"); // true
OrderStatus.ContainsValue(99); // false

// Enumeration
IReadOnlyList<OrderStatus> all = OrderStatus.All;
IReadOnlyList<string> names = OrderStatus.Names;
IReadOnlyList<int> values = OrderStatus.Values;
int count = OrderStatus.Count; // compile-time constant
Performance

Benchmarks run on Apple M3 Max, .NET 9.0.8, BenchmarkDotNet v0.14.0.

MethodMeanAllocated
FromName5.48 ns0 B
TryFromName4.53 ns0 B
FromValue2.18 ns0 B
TryFromValue1.21 ns0 B
ContainsName4.54 ns0 B
ContainsValue1.18 ns0 B
GetAll0.76 ns0 B
GetCount~0 ns0 B

All lookups are O(1) via statically-cached dictionaries. Count is a compile-time constant.

JSON Serialization

Add LayeredCraft.OptimizedEnums.SystemTextJson for source-generated, zero-reflection JsonConverter support. One package is all you need — it pulls in the core package automatically:

dotnet add package LayeredCraft.OptimizedEnums.SystemTextJson

Decorate your class with [OptimizedEnumJsonConverter] and the generator emits a concrete, AOT-safe converter and wires it up via [JsonConverter]:

using LayeredCraft.OptimizedEnums;
using LayeredCraft.OptimizedEnums.SystemTextJson;

[OptimizedEnumJsonConverter(OptimizedEnumJsonConverterType.ByName)]
public sealed partial class OrderStatus : OptimizedEnum<OrderStatus, int>
{
public static readonly OrderStatus Pending = new(1, nameof(Pending));
public static readonly OrderStatus Paid = new(2, nameof(Paid));
public static readonly OrderStatus Shipped = new(3, nameof(Shipped));

private OrderStatus(int value, string name) : base(value, name) \{ }
}
{ "status": "Pending" }

Two strategies are available: ByName (serializes as the member name string) and ByValue (serializes as the underlying value). See the JSON Serialization docs for full details.

Entity Framework Core

Add LayeredCraft.OptimizedEnums.EFCore for source-generated, zero-reflection EF Core value converter support. One package is all you need — it pulls in the core package automatically:

dotnet add package LayeredCraft.OptimizedEnums.EFCore

Decorate your class with [OptimizedEnumEfCore] and the generator emits concrete ValueConverter classes and registration helpers:

using LayeredCraft.OptimizedEnums;
using LayeredCraft.OptimizedEnums.EFCore;

[OptimizedEnumEfCore(OptimizedEnumEfCoreStorage.ByValue)]
public sealed partial class OrderStatus : OptimizedEnum<OrderStatus, int>
{
public static readonly OrderStatus Pending = new(1, nameof(Pending));
public static readonly OrderStatus Paid = new(2, nameof(Paid));
public static readonly OrderStatus Shipped = new(3, nameof(Shipped));

private OrderStatus(int value, string name) : base(value, name) \{ }
}

Register conversions with the global convention hook in your DbContext:

protected override void ConfigureConventions(ModelConfigurationBuilder builder)
{
builder.ConfigureOptimizedEnums();
}

Two strategies are available: ByValue (stores the underlying value) and ByName (stores the member name string). See the Entity Framework Core docs for full details.

Installation
dotnet add package LayeredCraft.OptimizedEnums

Supports .NET 8.0, .NET 9.0, .NET 10.0.

Documentation

Full documentation is available at the LayeredCraft.OptimizedEnums docs site.

License

MIT

About

note

A new way to define enums - and efficiently manage them

How to use

Example (source csproj, source files)

This is the CSharp Project that references LayeredCraft.OptimizedEnums

<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<PropertyGroup>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="LayeredCraft.OptimizedEnums" Version="1.4.4" />
</ItemGroup>

</Project>

Generated Files

Those are taken from $(BaseIntermediateOutputPath)\GX

//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

#nullable enable

namespace EnumDemo;

[global::System.CodeDom.Compiler.GeneratedCode("LayeredCraft.OptimizedEnums.Generator", "1.4.4.0")]
partial class CarTypes
{
private static readonly global::System.Collections.ObjectModel.ReadOnlyCollection<global::EnumDemo.CarTypes> s_all =
global::System.Array.AsReadOnly(new global::EnumDemo.CarTypes[]
{
None,
Dacia,
Tesla,
BMW,
Mercedes
});

private static readonly global::System.Collections.ObjectModel.ReadOnlyCollection<string> s_names =
global::System.Array.AsReadOnly(new string[]
{
None.Name,
Dacia.Name,
Tesla.Name,
BMW.Name,
Mercedes.Name
});

private static readonly global::System.Collections.ObjectModel.ReadOnlyCollection<int> s_values =
global::System.Array.AsReadOnly(new int[]
{
None.Value,
Dacia.Value,
Tesla.Value,
BMW.Value,
Mercedes.Value
});

private static readonly global::System.Collections.Generic.Dictionary<string, global::EnumDemo.CarTypes> s_byName =
new global::System.Collections.Generic.Dictionary<string, global::EnumDemo.CarTypes>(5, global::System.StringComparer.Ordinal)
{
[None.Name] = None,
[Dacia.Name] = Dacia,
[Tesla.Name] = Tesla,
[BMW.Name] = BMW,
[Mercedes.Name] = Mercedes
};

private static readonly global::System.Collections.Generic.Dictionary<int, global::EnumDemo.CarTypes> s_byValue =
new global::System.Collections.Generic.Dictionary<int, global::EnumDemo.CarTypes>(5)
{
[None.Value] = None,
[Dacia.Value] = Dacia,
[Tesla.Value] = Tesla,
[BMW.Value] = BMW,
[Mercedes.Value] = Mercedes
};

[global::System.CodeDom.Compiler.GeneratedCode("LayeredCraft.OptimizedEnums.Generator", "1.4.4.0")]
public static global::System.Collections.Generic.IReadOnlyList<global::EnumDemo.CarTypes> All => s_all;

[global::System.CodeDom.Compiler.GeneratedCode("LayeredCraft.OptimizedEnums.Generator", "1.4.4.0")]
public static global::System.Collections.Generic.IReadOnlyList<string> Names => s_names;

[global::System.CodeDom.Compiler.GeneratedCode("LayeredCraft.OptimizedEnums.Generator", "1.4.4.0")]
public static global::System.Collections.Generic.IReadOnlyList<int> Values => s_values;

[global::System.CodeDom.Compiler.GeneratedCode("LayeredCraft.OptimizedEnums.Generator", "1.4.4.0")]
public const int Count = 5;

[global::System.CodeDom.Compiler.GeneratedCode("LayeredCraft.OptimizedEnums.Generator", "1.4.4.0")]
public static global::EnumDemo.CarTypes FromName(string name)
{
if (!s_byName.TryGetValue(name, out var result))
throw new global::System.Collections.Generic.KeyNotFoundException(
$"'{name}' is not a valid name for CarTypes");

return result;
}

[global::System.CodeDom.Compiler.GeneratedCode("LayeredCraft.OptimizedEnums.Generator", "1.4.4.0")]
public static bool TryFromName(string name, [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out global::EnumDemo.CarTypes? result) =>
s_byName.TryGetValue(name, out result);

[global::System.CodeDom.Compiler.GeneratedCode("LayeredCraft.OptimizedEnums.Generator", "1.4.4.0")]
public static global::EnumDemo.CarTypes FromValue(int value)
{
if (!s_byValue.TryGetValue(value, out var result))
throw new global::System.Collections.Generic.KeyNotFoundException(
$"'{value}' is not a valid value for CarTypes");

return result;
}

[global::System.CodeDom.Compiler.GeneratedCode("LayeredCraft.OptimizedEnums.Generator", "1.4.4.0")]
public static bool TryFromValue(int value, [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out global::EnumDemo.CarTypes? result) =>
s_byValue.TryGetValue(value, out result);

[global::System.CodeDom.Compiler.GeneratedCode("LayeredCraft.OptimizedEnums.Generator", "1.4.4.0")]
public static bool ContainsName(string name) => s_byName.ContainsKey(name);

[global::System.CodeDom.Compiler.GeneratedCode("LayeredCraft.OptimizedEnums.Generator", "1.4.4.0")]
public static bool ContainsValue(int value) => s_byValue.ContainsKey(value);
}

Useful

Download Example (.NET C#)

Share LayeredCraft.OptimizedEnums

https://ignatandrei.github.io/RSCG_Examples/v2/docs/LayeredCraft.OptimizedEnums

Category "Enum" has the following generators:

1 Aigamo.MatchGenerator Nuget GitHub Repo stars 2026-04-08

2 CredFetoEnum Nuget GitHub Repo stars 2023-10-12

3 EnumClass Nuget GitHub Repo stars 2023-08-08

4 EnumsEnhanced Nuget GitHub Repo stars 2025-08-05

5 EnumUtilities Nuget GitHub Repo stars 2024-04-05

6 Flaggen Nuget GitHub Repo stars 2025-07-23

7 FusionReactor Nuget GitHub Repo stars 2024-04-06

8 Genbox.FastEnum Nuget GitHub Repo stars 2025-08-03

9 jos.enumeration Nuget GitHub Repo stars 2025-07-20

10 LayeredCraft.OptimizedEnums Nuget GitHub Repo stars 2026-09-06

11 LinkDotNet.Enumeration Nuget GitHub Repo stars 2026-05-14

12 NetEscapades.EnumGenerators Nuget GitHub Repo stars 2023-04-16

13 PMart.Enumeration NugetNuget GitHub Repo stars 2025-03-25

14 Porticle.Enumly Nuget GitHub Repo stars 2026-07-02

15 RapidEnum Nuget GitHub Repo stars 2025-10-04

16 requiredenum Nuget GitHub Repo stars 2025-08-14

17 TaggedEnum Nuget GitHub Repo stars 2026-04-05

See category

Enum