Source Generators
Nexum.SourceGenerators is an optional Roslyn incremental source generator that accelerates dispatch. The runtime in Nexum works standalone without it — you can start without the generator and opt in later when you need the extra performance or compile-time safety.
Tiered architecture
The generator ships three tiers, each building on the previous one.
| Tier | Technique | Overhead vs Runtime | Allocations |
|---|---|---|---|
| 1 — Runtime | Polymorphic handler cache, reflection-based resolution | baseline | 0 B |
| 2 — Compiled Pipeline | Source-generated pipeline delegates, monomorphized dispatch | 1.32× faster | 0 B |
| 3 — Interceptors | Roslyn Interceptors replace DispatchAsync call sites at compile time |
1.52× faster | 0 B |
All tiers produce zero allocations on the hot path. Tier 3 uses Roslyn Interceptors (stable since .NET 9.0.2xx SDK) to eliminate virtual dispatch entirely — the compiler rewrites the call site to point directly at the generated handler wrapper.
What the generator does
Tier 1 — DI registration and diagnostics
- Scans the compilation for types annotated with
[CommandHandler],[QueryHandler],[StreamQueryHandler],[NotificationHandler]usingForAttributeWithMetadataName(about 99× faster than traditionalSyntaxReceiver). - Emits a
services.AddNexum()partial method that registers every handler it found. - Reports compile-time diagnostics:
NEXUM001— handler type must not be abstract.NEXUM002— handler must implement the correct interface for its attribute.NEXUM003— duplicate handler registration for the same command/query.NEXUM004— notification exception handler must target a valid notification type.
Tier 2 — Compiled pipelines
For every command/query the generator walks the DI graph and emits a strongly typed delegate chain. The pipeline builder is bypassed entirely at dispatch time.
Tier 3 — Interceptors
The generator emits an InterceptsLocationAttribute on a method that replaces the ICommandDispatcher.DispatchAsync call site. The runtime still ships the virtual dispatcher as a fallback for cases the compiler can't statically resolve (reflection-driven dispatch, dynamic command types, etc.).
Enabling the generator
dotnet add package Nexum.SourceGenerators
That's it. The package is marked DevelopmentDependency="true" and ships as an analyzer — no runtime assembly, no NuGet graph pollution for your consumers.
Enable interceptors (Tier 3) in your project file:
<PropertyGroup>
<InterceptorsPreviewNamespaces>$(InterceptorsPreviewNamespaces);Nexum.Generated</InterceptorsPreviewNamespaces>
</PropertyGroup>
Source Generator vs Runtime — when to choose which?
- Start with Runtime. It's fast enough for 99% of apps (1.5× faster than MediatR already).
- Add the generator when you want compile-time safety for handler discovery, or when profiling shows dispatch overhead matters.
- Enable interceptors for latency-critical hot paths where every nanosecond counts.
The dual-path design (System.Text.Json pattern) means your code does not change when you adopt or remove the generator — only the .csproj does.