EnumRecords 0.4.0
See the version list below for details.
dotnet add package EnumRecords --version 0.4.0
NuGet\Install-Package EnumRecords -Version 0.4.0
<PackageReference Include="EnumRecords" Version="0.4.0"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
<PackageVersion Include="EnumRecords" Version="0.4.0" />
<PackageReference Include="EnumRecords"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
paket add EnumRecords --version 0.4.0
#r "nuget: EnumRecords, 0.4.0"
#:package EnumRecords@0.4.0
#addin nuget:?package=EnumRecords&version=0.4.0
#tool nuget:?package=EnumRecords&version=0.4.0
EnumRecords
A C# source generator that associates compile-time constant data properties with enum values, enabling property-like access via generated extension methods.
Features
- 🚀 Zero runtime overhead — All code is generated at compile time
- 📦 No runtime dependencies — Attributes are source-generated into your project
- 🔍 IntelliSense support — Full IDE autocomplete for generated extension methods
- ✅ Type-safe — Compile-time validation of property types and values
- 🎯 Simple API — Just two attributes to learn
- 🔄 Reverse lookup — Find enum values by property values with
[ReverseLookup] - 📋 Collection access — Get all property values via
Get{PropertyName}s()methods
Installation
NuGet Package
dotnet add package EnumRecords
Note: EnumRecords is a development-only dependency. NuGet automatically configures it with
PrivateAssets="all"so it won't become a transitive dependency of your consumers.
Project Reference
For local development, add a reference to the generator project:
<ItemGroup>
<ProjectReference Include="path/to/EnumRecords.csproj"
OutputItemType="Analyzer"
ReferenceOutputAssembly="false" />
</ItemGroup>
Quick Start
1. Define a Properties Record Struct
Create a readonly record struct that defines the schema for your enum's associated data:
public readonly record struct ColorEnumProperties(
string Name,
int Value,
string HexCode
);
2. Decorate Your Enum
Apply [EnumRecord<T>] to your enum and [EnumData(...)] to each member:
using EnumRecords;
[EnumRecord<ColorEnumProperties>]
public enum EColors : int
{
[EnumData("Red", 1, "#FF0000")]
Red = 1,
[EnumData("Green", 2, "#00FF00")]
Green = 2,
[EnumData("Blue", 3, "#0000FF")]
Blue = 3,
}
3. Access Properties via Extension Methods
The generator creates extension methods for each property in your record struct:
// Access properties like methods on enum values
string hex = EColors.Red.HexCode(); // "#FF0000"
string name = EColors.Green.Name(); // "Green"
int value = EColors.Blue.Value(); // 3
// Works with variables too
EColors color = EColors.Red;
Console.WriteLine(color.HexCode()); // "#FF0000"
// Iterate over all values
foreach (EColors c in Enum.GetValues<EColors>())
{
Console.WriteLine($"{c}: {c.Name()} - {c.HexCode()}");
}
Supported Property Types
The [EnumData] attribute accepts any compile-time constant values:
| Type | Example |
|---|---|
string |
"Hello" |
int, long, short, byte |
42, 100L |
uint, ulong, ushort, sbyte |
42U, 100UL |
float, double, decimal |
3.14f, 3.14d, 3.14m |
bool |
true, false |
char |
'A' |
Reverse Lookup
You can mark properties with [ReverseLookup] to generate methods that find an enum value by its property value:
Setup
Add [ReverseLookup] to the constructor parameter in your properties record struct:
public readonly record struct ColorEnumProperties(
string Name,
int Value,
[ReverseLookup] string HexCode // Enable reverse lookup for HexCode
);
Generated Methods
For each property marked with [ReverseLookup], two static methods are generated:
// Non-throwing variant - returns false if not found
public static bool TryFromHexCode(string value, out EColors result);
// Throwing variant - throws ArgumentException if not found
public static EColors FromHexCode(string value);
Usage
// Find enum by property value (throwing)
EColors red = EColorsExtensions.FromHexCode("#FF0000"); // Returns EColors.Red
// Find enum by property value (non-throwing)
if (EColorsExtensions.TryFromHexCode("#00FF00", out var color))
{
Console.WriteLine(color); // Green
}
// Handle not found
if (!EColorsExtensions.TryFromHexCode("#FFFFFF", out _))
{
Console.WriteLine("Color not found");
}
// Throwing variant for unknown values
try
{
var unknown = EColorsExtensions.FromHexCode("#FFFFFF");
}
catch (ArgumentException ex)
{
// "No EColors found with HexCode '#FFFFFF'"
}
Uniqueness Requirement
Properties marked with [ReverseLookup] must have unique values across all enum members. The generator emits a compile-time error (ENUMREC001) if duplicate values are detected:
// ❌ This will cause compile error ENUMREC001
public readonly record struct BadProps([ReverseLookup] string Code);
[EnumRecord<BadProps>]
public enum BadEnum
{
[EnumData("A")]
First,
[EnumData("A")] // Error: Duplicate value '"A"' for reverse-lookup property 'Code'
Second,
}
Case-Insensitive String Lookup
For string properties, you can enable case-insensitive lookups with IgnoreCase = true:
public readonly record struct FileTypeProperties(
string Extension,
[ReverseLookup(IgnoreCase = true)] string MimeType
);
[EnumRecord<FileTypeProperties>]
public enum FileType
{
[EnumData(".json", "application/json")]
Json,
[EnumData(".xml", "application/xml")]
Xml,
}
// Usage - all these will match FileType.Json
FileTypeExtensions.FromMimeType("application/json"); // exact match
FileTypeExtensions.FromMimeType("APPLICATION/JSON"); // uppercase
FileTypeExtensions.FromMimeType("Application/Json"); // mixed case
Note: When using
IgnoreCase = true, the uniqueness check also uses case-insensitive comparison. For example,"ABC"and"abc"would be considered duplicates.
Ignoring Enum Members
Use [Ignore] to exclude specific enum members from property mappings. This is useful for sentinel values like None, Unknown, or deprecated entries.
Setup
using EnumRecords;
[EnumRecord<FileTypeProperties>]
public enum FileType
{
[Ignore] // No properties required, excluded from all generated code
Unknown = 0,
[EnumData(".json", "application/json")]
Json,
[EnumData(".xml", "application/xml")]
Xml,
}
Behavior
Members marked with [Ignore]:
- Do not require
[EnumData]— no compile error for missing properties - Are excluded from generated extension methods — calling
.Extension()on an ignored member throwsArgumentOutOfRangeException - Are excluded from
Get{PropertyName}s()collections - Are excluded from reverse lookup methods
// Ignored members throw when accessing properties
try
{
var ext = FileType.Unknown.Extension();
}
catch (ArgumentOutOfRangeException)
{
// Expected - Unknown is not mapped
}
// Ignored members are not in collections
var extensions = FileTypeExtensions.GetExtensions(); // [".json", ".xml"] - no Unknown
// Reverse lookup won't return ignored members
FileTypeExtensions.TryFromMimeType("unknown", out _); // false
Note: If you have a conflict with another
[Ignore]attribute (e.g., from NUnit or MSTest), use the fully qualified name:[EnumRecords.Ignore]
Get All Property Values
For each property in your record struct, the generator creates a Get{PropertyName}s() method that returns all defined values as a read-only list:
Generated Methods
// For ColorEnumProperties with Name, Value, and HexCode properties:
public static IReadOnlyList<string> GetNames();
public static IReadOnlyList<int> GetValues();
public static IReadOnlyList<string> GetHexCodes();
Usage
// Get all property values as collections
var names = EColorsExtensions.GetNames(); // ["Red", "Green", "Blue"]
var values = EColorsExtensions.GetValues(); // [1, 2, 3]
var hexCodes = EColorsExtensions.GetHexCodes(); // ["#FF0000", "#00FF00", "#0000FF"]
// Useful for validation, dropdowns, etc.
if (EColorsExtensions.GetHexCodes().Contains(userInput))
{
// Valid hex code
}
// Or with FileType enum
var extensions = FileTypeExtensions.GetExtensions(); // [".json", ".xml", ".csv"]
var mimeTypes = FileTypeExtensions.GetMimeTypes(); // ["application/json", "application/xml", "text/csv"]
Advanced Examples
HTTP Status Codes
public readonly record struct HttpStatusProperties(
int Code,
string Phrase,
bool IsSuccess
);
[EnumRecord<HttpStatusProperties>]
public enum HttpStatus
{
[EnumData(200, "OK", true)]
Ok = 200,
[EnumData(201, "Created", true)]
Created = 201,
[EnumData(400, "Bad Request", false)]
BadRequest = 400,
[EnumData(404, "Not Found", false)]
NotFound = 404,
[EnumData(500, "Internal Server Error", false)]
InternalServerError = 500,
}
// Usage
if (HttpStatus.Ok.IsSuccess())
{
Console.WriteLine(HttpStatus.Ok.Phrase()); // "OK"
}
File Types
public readonly record struct FileTypeProperties(
string Extension,
string MimeType,
string Description
);
[EnumRecord<FileTypeProperties>]
public enum FileType
{
[EnumData(".json", "application/json", "JSON Document")]
Json,
[EnumData(".xml", "application/xml", "XML Document")]
Xml,
[EnumData(".csv", "text/csv", "Comma-Separated Values")]
Csv,
}
// Usage
string mime = FileType.Json.MimeType(); // "application/json"
API Reference
EnumRecordAttribute<TProperties>
Marks an enum as having associated record properties.
[EnumRecord<TProperties>]
public enum MyEnum { ... }
TPropertiesmust be astruct(typically areadonly record struct)- Applied to the enum declaration
EnumDataAttribute
Specifies the property values for an enum member.
[EnumData(arg1, arg2, ...)]
EnumMember = value,
- Arguments are positional and must match the order of the properties record struct's constructor parameters
- All arguments must be compile-time constants
ReverseLookupAttribute
Marks a property for reverse lookup, enabling lookup of enum values by property value.
public readonly record struct MyProperties([ReverseLookup] string UniqueId);
- Applied to constructor parameters of the properties record struct
- Property values must be unique across all enum members (enforced at compile time)
- Generates
TryFrom{PropertyName}andFrom{PropertyName}static methods
Properties:
| Property | Type | Default | Description |
|---|---|---|---|
IgnoreCase |
bool |
false |
Enable case-insensitive matching for string lookups |
IgnoreAttribute
Excludes an enum member from property mappings and generated code.
[Ignore]
EnumMember = value,
- Applied to enum members (fields)
- Member does not require
[EnumData] - Excluded from extension methods, collections, and reverse lookups
Requirements
- .NET 6.0+ or .NET Standard 2.0+ consuming project
- C# 9.0+ (for record struct support in consuming code)
Building from Source
# Clone the repository
git clone https://github.com/dsisco11/EnumRecords.git
cd EnumRecords
# Build the generator
dotnet build EnumRecords.csproj
# Build and run tests
dotnet run --project EnumRecords.Tests/EnumRecords.Tests.csproj
How It Works
- Post-Initialization: The generator emits the
EnumRecordAttribute<T>andEnumDataAttributetypes as source code into your compilation - Syntax Analysis: Finds all enums decorated with
[EnumRecord<T>] - Semantic Analysis: Extracts the properties type
Tand reads constructor parameters to determine property names and types - Code Generation: For each decorated enum, generates a static extension class with one method per property using switch expressions
License
This project is licensed under the MIT License - see the LICENSE.txt file for details.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Learn more about Target Frameworks and .NET Standard.
-
.NETStandard 2.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.