.NETSource GeneratorsPerformanceRoslynopen source

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.ResultsResult<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.