Theodicean.SourceGenerators
0.0.4
dotnet add package Theodicean.SourceGenerators --version 0.0.4
NuGet\Install-Package Theodicean.SourceGenerators -Version 0.0.4
<PackageReference Include="Theodicean.SourceGenerators" Version="0.0.4" />
<PackageVersion Include="Theodicean.SourceGenerators" Version="0.0.4" />
<PackageReference Include="Theodicean.SourceGenerators" />
paket add Theodicean.SourceGenerators --version 0.0.4
#r "nuget: Theodicean.SourceGenerators, 0.0.4"
#:package Theodicean.SourceGenerators@0.0.4
#addin nuget:?package=Theodicean.SourceGenerators&version=0.0.4
#tool nuget:?package=Theodicean.SourceGenerators&version=0.0.4
Theodicean.SourceGenerators
Source generator for fast, allocation-light System.Text.Json converters for enums, driven by attributes.
Enables serialization/deserialization of arbitrary string tokens for enums (including tokens that are not valid C# identifiers, e.g., values with spaces, hyphens, or starting digits) while avoiding runtime reflection for performance and NativeAOT friendliness.
Why
- Non-identifier tokens: Many wire formats use names that aren’t valid C# enum identifiers (e.g., "not-found", "401", "connection refused"). Use
Display(Name = "...")orDescription("...")to map those tokens to legal enum members. - Reflection-free and AOT-friendly: The converter is fully source-generated. No runtime reflection or metadata scanning, making it safe for trimming and NativeAOT.
- Performance: Uses
Utf8JsonReader.CopyString,stackalloc, andArrayPool<char>with ordinal comparisons for low-allocation, fast parsing.
Install
Package (project using the generator):
Add a PackageReference to
Theodicean.SourceGeneratorsExample
csprojsnippet:<ItemGroup> <PackageReference Include="Theodicean.SourceGenerators" Version="x.y.z" PrivateAssets="all" ExcludeAssets="runtime" /> </ItemGroup>
The generated code uses features that require dotnet 9 or later.
Attributes: Follows the same logic as NetEscapades.EnumGenerators - just replace
NETESCAPADES_ENUMGENERATORS_EMBED_ATTRIBUTESwithTHEODICEAN_GENERATORS_EMBED_ATTRIBUTES.
Example:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<DefineConstants>$(DefineConstants);THEODICEAN_GENERATORS_EMBED_ATTRIBUTES</DefineConstants>
</PropertyGroup>
</Project>
What it generates
Annotate a partial class with EnumJsonConverterAttribute, pointing to the enum you want to serialize/deserialize. The generator emits a sealed JsonConverter<TEnum> that:
- Read: Parses a JSON string into the enum value using a high-performance
ReadOnlySpan<char>path and optional case sensitivity. - Write: Emits the chosen string representation for each enum value.
- Names: Uses the enum field name by default, or the
Display(Name = "...")/Description("...")value if present (both the attribute value and the enum member name will be matched). - Errors: Throws
JsonExceptionon invalid input. IfPropertyNameis set, it is included in the exception for better diagnostics. - Reflection-free: No runtime reflection; code is generated at build time.
- NativeAOT/Trimming friendly: Works under trimming and NativeAOT scenarios.
Usage
- Define your enum. You can optionally decorate members with
Display(Name = "...")(orDescription("...")) to control the serialized string.
using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;
using Theodicean.SourceGenerators;
[EnumJsonConverter<ExampleEnum>(CaseSensitive = false, PropertyName = "error")]
public enum ExampleEnum
{
None = 1,
[Display(Name = "NOT_FOUND")] NotFound,
[Display(Name = "CONNECTION_REFUSED")] ConnectionRefused
}
- Optionally declare a partial converter class where you want it in the same assembly as the enum:
public partial class ExampleEnumJsonConverter;
- Annotate your enum so that the converter is used.
using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;
using Theodicean.SourceGenerators;
[EnumJsonConverter<ExampleEnum>(CaseSensitive = false, PropertyName = "error")]
[JsonConverter(typeof(ExampleEnumJsonConverter))]
public enum ExampleEnum
{
None = 1,
[Display(Name = "NOT_FOUND")] NotFound,
[Display(Name = "CONNECTION_REFUSED")] ConnectionRefused
}
Or add it as a converter in your JsonSerializerOptions
new JsonSerializerOptions { Converters = { new ExampleEnumJsonConverter() } }
NOTE: If you've added the JsonNumberEnumConverter to your JsonSerializerOptions, the custom converter must be added before JsonNumberEnumConverter or the custom converter will not be called.`
Attribute options
- EnumJsonConverter(Type enumType): Required. The enum type to generate a converter for.
- CaseSensitive (bool): Default
false. Iftrue, only exact (ordinal) case matches are accepted when reading JSON. - CamelCase (bool): Default
false. IfPropertyNameis supplied andCamelCase = true, the property name included in thrownJsonExceptionis camel-cased. - PropertyName (string?): If set, included in
JsonExceptionto identify the logical field name when invalid input is encountered.
Display/Description name mapping
- If an enum member has
[Display(Name = "VALUE")], that string is used for both serialization and deserialization. - If no
Displayis present but[Description("VALUE")]exists, the description string is used. - If neither is present, the enum member name is used.
- When
CaseSensitive = false(default), comparisons useStringComparison.OrdinalIgnoreCase. - Deserialization of default enum member name will always work, regardless of
Display/Descriptionattributes.
Example of serialized values
Given the ExampleEnum enum above, JSON will contain strings like "NONE", "NOT_FOUND", etc. If a value is not recognized, a JsonException is thrown. When PropertyName = "error", the exception includes that property name for better error messages.
Limitations
- .NET version: Requires .NET 9 or later to use the generated converters.
- System.Text.Json only: Generates converters specifically for
System.Text.Json. - Enums only: This generator is for enums. Other types are not supported.
- Public vs internal: The emitted converter matches the visibility of your partial class (
publicorinternal). Ensure accessibility aligns with your usage. - String tokens only: The converter expects JSON string tokens for enum values. Numeric tokens aren’t supported by this converter.
- Name collisions: If multiple enum members map to the same string (via
Display/Descriptionor names), deserialization picks the first match by declaration order; serialization will produce the shared string.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. 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 was computed. 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 was computed. 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 was computed. 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 | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. 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.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.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.0.4 | 1,173 | 2/18/2026 |
| 0.0.4-pre01 | 105 | 2/17/2026 |
| 0.0.3 | 1,811 | 12/14/2025 |
| 0.0.3-pre03 | 194 | 12/13/2025 |
| 0.0.3-pre02 | 169 | 12/13/2025 |
| 0.0.3-pre01 | 127 | 12/13/2025 |
| 0.0.2 | 496 | 12/11/2025 |
| 0.0.2-pre02 | 437 | 12/11/2025 |
| 0.0.2-pre01 | 431 | 12/11/2025 |
| 0.0.1 | 1,474 | 8/10/2025 |
| 0.0.1-pre7 | 196 | 8/10/2025 |
| 0.0.1-pre6 | 199 | 8/10/2025 |
| 0.0.1-pre5 | 200 | 8/10/2025 |
| 0.0.1-pre4 | 208 | 8/9/2025 |