Building Zero-Allocation .NET with Source Generators
Every time your mediator looks up a handler, it’s probably doing a dictionary lookup, a virtual dispatch, and maybe a bit of reflection. For most apps that’s fine. For hot paths — message queues, game loops, real-time systems — it adds up.
The ZeroAlloc suite takes a different approach: do all that wiring at compile time using Roslyn source generators, and eliminate the runtime overhead entirely.
What’s In the Suite
ZeroAlloc.Mediator — compile-time mediator. The source generator scans your assemblies, finds every IRequestHandler<TRequest, TResponse>, and emits a static dispatch switch. No dictionary, no reflection, no virtual dispatch. Handler resolution costs zero allocations at runtime.
ZeroAlloc.Inject — compile-time DI container. Instead of a runtime-built service graph, the generator emits a typed container with direct constructor calls. Native AOT compatible, 5 ns startup.
ZeroAlloc.Results — Result<T, E> with full CSharpFunctionalExtensions API parity and zero boxing.
ZeroAlloc.Validation — validation rules wired at compile time. Write your rules as types; the generator builds the evaluation pipeline.
ZeroAlloc.ValueObjects — source-generated equality for value objects, eliminating the boxing that GetEqualityComponents() normally causes.
ZeroAlloc.Specification — source-generated specification pattern for .NET 8+.
How It Works
Each library follows the same pattern. You write normal C# — interfaces, attributes, partial classes. The source generator reads your code through the Roslyn compilation model, emits concrete implementations, and the compiler weaves them in. You get IntelliSense, compile-time errors, and zero reflection at runtime.
// You write this
[GenerateDispatcher]
public partial class Dispatcher : IMediator { }
// Generator emits something like this
public partial class Dispatcher
{
public TResponse Send<TResponse>(IRequest<TResponse> request) =>
request switch {
CreateOrderCommand cmd => _createOrderHandler.Handle(cmd),
GetOrderQuery q => _getOrderHandler.Handle(q),
_ => throw new InvalidOperationException()
};
}
No dictionaries. No Activator.CreateInstance. No allocations.
Available on NuGet: ZeroAlloc.Mediator · ZeroAlloc.Inject · ZeroAlloc.Results · ZeroAlloc.Validation · ZeroAlloc.ValueObjects · ZeroAlloc.Specification
Source on GitHub · Native AOT compatible.