Library / SDK
xin9le/FastEnum avatar
xin9le/FastEnum

FastEnum is System.Enum without the reflection tax

The world fastest enum utilities for C#/.NET

523 stars31 forksC#MIT

At a glance

What is it?
FastEnum is a .NET library of enum helpers that mirror the shape of System.Enum but avoid its reflection cost and allocations, caching enum metadata on first use and optionally generating source code instead. It also documents two things it refuses to do, generics only and no comma separated flag parsing, which tells you more about the trade-off than the benchmark screenshot does.
Who is it for?
FastEnum fits a .NET service where enum to string conversion or flag checking sits in a hot loop, and it does not fit a team that has not profiled that path, since the caching approach alone already outperforms the framework calls according to the project itself.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 89 days ago.
What is it written in?
Mainly C#, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Why enum conversion ends up in a hot loop

The premise of FastEnum is stated in the opening line: it is a set of extremely fast enum utilities for C# and .NET, provided methods are all achieved zero allocation, and they are designed to be easy to use like System.Enum. The author's reasoning follows, and it is the reasoning any backend engineer will recognise.

Enum is a genuinely popular feature, and the framework's enum helpers are built on reflection. Enum.GetName and Enum.ToString on a hot path are not free, and in a service that converts an enum to a string for every log line or every serialization call, that cost adds up. FastEnum's claim is that you can keep the familiar API and pay a much smaller price for it.

That framing matters for how you should read the rest of the repository. This is not a new enum type, it is not a source generator that changes how you declare enums, and it is not a serialization library. It is a drop-in shaped set of static helpers, plus a set of conveniences for the enum metadata that application code tends to reinvent badly, such as mapping an enum member to a display label.

The intended user is a .NET developer who has noticed enum conversion showing up in a profile. The project is published on NuGet as FastEnum, with a Releases badge and a build and test workflow badge in the README, and the repository root is small, with src/, nuget/ and assets/ directories, which is what a focused library looks like.

The API is a rename of System.Enum, not a redesign

The migration story is the strongest part of the pitch, and it is shown as a side by side comparison. The FastEnum side looks like this.

cs
//--- FastEnum
var values = FastEnum.GetValues<Fruits>();
var names = FastEnum.GetNames<Fruits>();
var name = FastEnum.GetName(Fruits.Apple);
var toString = Fruits.Apple.FastToString();
var defined = FastEnum.IsDefined(Fruits.Apple);
var parse = FastEnum.Parse<Fruits>("Apple");
var tryParse = FastEnum.TryParse<Fruits>("Apple", out var value);

And the framework equivalent is this.

cs
//--- .NET
var values = Enum.GetValues<Fruits>();
var names = Enum.GetNames<Fruits>();
var name = Enum.GetName(Fruits.Apple);
var toString = Fruits.Apple.ToString();
var defined = Enum.IsDefined(Fruits.Apple);
var parse = Enum.Parse<Fruits>("Apple");
var tryParse = Enum.TryParse<Fruits>("Apple", out var value);

The mapping is one to one, with two deliberate differences. The type is specified generically everywhere, including in the IsDefined and GetName calls, and the string conversion is an extension method named FastToString rather than a plain ToString, because ToString is already taken on the enum type and cannot be replaced by an extension method with the same name.

So adopting it is a search and replace across the call sites, plus a small naming adjustment for the string conversion, and the compiler will point at every place you need to look. That is a very different upgrade experience from libraries that ask you to change how you declare your types.

Caching on first call, or generating the code instead

The mechanism has two tiers, and the README is explicit that the first is the default and the second is for a specific situation.

FastEnum is fundamentally implemented by caching enum metadata upon its initial invocation. The author says this approach alone achieves speeds that significantly surpass those of standard .NET and that it is the optimal choice for the majority of users. The later section on why it is fast describes the technique: static type caching, so the reading cost is almost zero, techniques for avoiding allocation, and a specialized dictionary for the specific key used internally.

The second tier arrived in v2 as a source code generation API, for what the README calls mission-critical scenarios where the ultimate pursuit of speed is paramount. The shape of it is a generator attribute on a placeholder partial class.

cs
[FastEnum<HttpStatusCode>]  // Annotate target enum type
partial class HttpStatusCodeBooster  // Placeholder for source code generation
{ }

var x1 = FastEnum.ToString<HttpStatusCode, HttpStatusCodeBooster>(HttpStatusCode.OK);
var x2 = FastEnum.IsDefined<HttpStatusCode, HttpStatusCodeBooster>(HttpStatusCode.OK);
var x3 = FastEnum.Parse<HttpStatusCode, HttpStatusCodeBooster>("OK");
var x4 = FastEnum.TryParse<HttpStatusCode, HttpStatusCodeBooster>("OK", out var value);

The cost of that tier is real and worth being clear about. You need one placeholder partial class per enum you want generated, the source generator has to run as part of your build, and the API gains a second type parameter everywhere. For a library that most people will use through the caching path, that is a trade you should make deliberately, per enum, rather than adopt everywhere on day one.

Member, EnumMemberAttribute and a LabelAttribute of your own

Beyond the System.Enum mirror, the library adds three conveniences that address real friction in application code.

The first is pairwise member information. Member<TEnum> carries the value, the name and the FieldInfo of an enum member, and it supports deconstruction, so a name and value pair comes apart cleanly. The FieldInfo is included, and the README says to use it for reflection code, which is the case where people usually end up writing their own reflection helper.

cs
class Member<TEnum>
{
    public TEnum Value { get; }
    public string Name { get; }
    public FieldInfo FieldInfo { get; }
    // etc...
}

var member = Fruits.Apple.ToMember()!;
var (name, value) = member;  // Supports deconstruction

The second is a shortcut for EnumMemberAttribute.Value, which the author says they often see developers using as an alias for the field name, with a method that reads the value property quickly.

The third is a LabelAttribute of the project's own, because EnumMemberAttribute is specified with AllowMultiple set to false, and the author wanted to attach several labels to one field. The attribute takes an optional index, so a member can have a primary label and a secondary one.

cs
enum Company
{
    [Label("Apple, Inc.")]
    [Label("AAPL", 1)]
    Apple = 0,
}

var x1 = Company.Apple.GetLabel();   // Apple, Inc.
var x2 = Company.Apple.GetLabel(1);  // AAPL

These are small conveniences, but they are the kind that end up duplicated across a codebase, and having one tested implementation of the label lookup saves every project from writing its own.

Two limitations the README states plainly

The Limitation section is unusually honest, and both items are about the shape of the API rather than about bugs.

The first is that FastEnum provides only the generics version of its methods, for performance reasons. System.Enum has overloads that take a System.Type argument, and the author considers those too slow because of the boxing that happens. If your code needs the Type based overload, the README's instruction is to use the System.Enum version. That is a sensible trade, but it does mean FastEnum is not a universal replacement, and in code that works with runtime types you will end up with both libraries in the same file.

The second is that FastEnum cannot parse comma separated strings. System.Enum.Parse can parse a string like Apple, Melon into a combined flags value, and the author notes that this is a quietly existing specification that is not well known.

cs
//--- Passes comma-separated string
var value = Enum.Parse<Fruits>("Apple, Melon");
Console.WriteLine((int)value);  // 5

The reason for dropping it is that supporting that analysis adds overhead, and cutting the feature makes things faster. The author's own assessment is that the feature is rarely used, and says he has never used it in sixteen years of writing code. If your application parses flag values out of configuration or a query string, this is a real behavioural difference, and you will need System.Enum for those call sites.

Both limitations have the same shape. FastEnum is faster because it refuses to be general, and the cost of that refusal is visible in the API.

Platform targets and the 1.8.0 escape hatch

The support matrix is short. The current line targets .NET 8.0 and later, and the README marks that as important, with a pointer for anyone on older platforms to use v1.8.0 instead, which supports .NET Framework 4.6.1 and later, .NET Standard 2.0 and later, and .NET 5 and later.

That is a sensible arrangement for a performance library, since the older runtime cannot be assumed to have the same low level facilities available, but it means the version you use is decided by your target framework rather than by your preference. A company application still on .NET Framework has to take the 1.8.0 line and does not get the v2 source generator, so the two tiers of the design are not available together on the old platform.

The release history shows active work on the new line. v2.0.6 was published on 2025-11-17, v2.0.7 on 2026-07-10 and v2.0.8 on 2026-07-26, and the last push to the repository was on the same day as v2.0.8. The repository is not archived.

The licence is MIT, and the README describes the author as a developer in Japan who has been a Microsoft MVP for Developer Technologies since July 2012, which is a useful signal for a library you are considering putting in a hot path.

One note on the performance evidence. The README shows a benchmark image and the environment the numbers were produced on, and the environment block is included in the repository README itself.

ini
BenchmarkDotNet v0.15.8, Windows 11 (10.0.26200.8737/25H2/2025Update/HudsonValley2)
Intel Core Ultra 7 155H 3.00GHz, 1 CPU, 22 logical and 16 physical cores
.NET SDK 10.0.301

A single machine, a single enum shape and a synthetic loop. Treat the ratio as a reason to look at your own code, not as a number to quote.

When the framework is fast enough

The honest alternative is to do nothing, and the project itself nudges you in that direction by saying the caching approach alone is the optimal choice for the majority of users.

Enum conversion is only a problem where it happens many times with the same enum. A configuration parser that resolves an enum once at startup, a switch statement in a request handler that runs once per request, a log formatter that names one of five states, none of these need a library. Adding FastEnum to a codebase where enum conversion is not in a profile buys a dependency, a NuGet reference, and a set of API differences you have to remember, in exchange for a difference you cannot measure.

The source generation tier has the same shape of argument, one level up. It requires a placeholder type per enum, a generator in the build, and a two type parameter call signature, and it only pays off in the case the README describes as mission critical and the pursuit of speed being paramount. If you cannot name the loop where this matters, that is the answer.

There is a middle path worth knowing about, and it is the one the library's own design suggests. Use the cached API everywhere it is a clean substitution, which is most call sites, and reserve the generated boosters for the two or three enums that your own measurements show are hot. That keeps the dependency small, keeps the migration mechanical and keeps the expensive part of the design scoped to where it earns its place.

One more constraint to keep in mind when you plan the migration. Because the API is generics only, code that reflects over enum types at runtime cannot use FastEnum, and code that parses comma separated flag values cannot use it either. Both of those are common in exactly the places, configuration handling and plugin systems, where enums are converted from strings most often.

Editorial conclusion

FastEnum fits a .NET service where enum to string conversion or flag checking sits in a hot loop, and it does not fit a team that has not profiled that path, since the caching approach alone already outperforms the framework calls according to the project itself. Before you adopt it, measure the enum to string conversion in your own code rather than trusting the benchmark image, and decide whether the v2 source generator is worth the extra build step, because it is the only part of the library that changes how your project is built. The last push was on 2026-07-26, the newest release is v2.0.8 from the same day, and the licence is MIT.

Frequently asked questions

How do I install FastEnum in a .NET project?

FastEnum is published on NuGet and the README gives a single command, dotnet add package FastEnum. The current v2 line targets .NET 8.0 and later, and for older platforms the README points you to v1.8.0, which supports .NET Framework 4.6.1, .NET Standard 2.0 and .NET 5.

How is FastEnum different from System.Enum?

The API mirrors System.Enum with the same method names for GetValues, GetNames, GetName, IsDefined, Parse and TryParse, with the enum type always given generically, and the string conversion exposed as the FastToString extension method. The difference is the implementation, which caches enum metadata on first use to avoid the reflection and allocation cost of the framework calls.

What does the FastEnum source generator do?

Introduced in v2, it generates the enum helpers at build time instead of caching them at runtime. You annotate a placeholder partial class with the FastEnum attribute for the target enum and then call the generated overloads that take both the enum type and the booster type. The README positions it for mission-critical cases where speed matters more than the extra build step.

Can FastEnum parse comma separated flag values?

No, and the README states this as a deliberate limitation. System.Enum.Parse can parse a string such as Apple, Melon into a combined flags value, but supporting that analysis adds overhead, so FastEnum drops it and the README suggests using the System.Enum version for that case.

Does FastEnum have Type based overloads like System.Enum?

No. The README explains that only the generics versions are provided, because the overloads that take a System.Type argument are too slow due to the boxing involved. If you need the Type based methods, the README says to use the System.Enum version.

Official sources

  1. Issues
  2. License: MIT
  3. README
  4. Releases
  5. xin9le/FastEnum on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/xin9le-fastenum.svg)](https://hysenlabs.com/projects/xin9le-fastenum)

Was this useful?