✨ Roslyn source generator — Result types auto-injected, Try* wrappers generated at build time

AutoResult.Generator
Compile-time Result<T> monad for .NET.

Always emits Result<T>, Result<T,TError>, Unit, and ResultExtensions — then [TryWrap] generates safe Try*() wrappers for every public method.

$ dotnet add package AutoResult.Generator
your service
using AutoResult;

[TryWrap]
public partial class OrderService
{
    public int GetOrderId(string name) => 42;

    public void ProcessOrder(int id) { /* ... */ }

    public async Task<Order> FetchOrderAsync(
        int id,
        CancellationToken ct = default)
        => await _repo.GetAsync(id, ct);
}
generated at build time
// ✨ AutoResult.g.cs
public partial class OrderService
{
    public Result<int> TryGetOrderId(string name)
    {
        try { return Result<int>.Ok(GetOrderId(name)); }
        catch (Exception ex) { return Result<int>.Fail(ex); }
    }

    public Result<Unit> TryProcessOrder(int id)
    {
        try { ProcessOrder(id); return Result<Unit>.Ok(Unit.Value); }
        catch (Exception ex) { return Result<Unit>.Fail(ex); }
    }
}

Everything you need

Result types, wrappers, and composition helpers generated into your project with zero runtime ceremony.

📦

Always-Available Types

Result<T>, Result<T,TError>, Unit, and ResultExtensions are injected into every compilation automatically.

Zero Boilerplate

Add [TryWrap] to a partial class and the generator emits Try*() wrappers for all public instance methods automatically.

🔁

All Method Kinds

Sync, void, async Task<T>, and async-void Task methods are all handled correctly.

🚂

Railway-Oriented

Compose success and failure paths with Map, Bind, and Match via ResultExtensions.

🪤

No Double-Wrapping

Methods already prefixed with Try are skipped automatically, so generated wrappers never collide with existing APIs.

🛡️

Compile-Time Diagnostics

AR001 and AR002 catch misuse during the build, not after your app is already running.

Examples

From attribute to generated wrappers to railway-style composition.

using AutoResult;

[TryWrap]
public partial class OrderService
{
    public int GetOrderId(string name) => 42;
    public void ProcessOrder(int id) { /* ... */ }
    public async Task<Order> FetchOrderAsync(int id, CancellationToken ct = default)
        => await _repo.GetAsync(id, ct);
}
// Auto-generated by AutoResult.Generator
public partial class OrderService
{
    public Result<int> TryGetOrderId(string name)
    {
        try { return Result<int>.Ok(GetOrderId(name)); }
        catch (Exception ex) { return Result<int>.Fail(ex); }
    }

    public Result<Unit> TryProcessOrder(int id)
    {
        try { ProcessOrder(id); return Result<Unit>.Ok(Unit.Value); }
        catch (Exception ex) { return Result<Unit>.Fail(ex); }
    }

    public async Task<Result<Order>> TryFetchOrderAsync(int id, CancellationToken ct = default)
    {
        try { return Result<Order>.Ok(await FetchOrderAsync(id, ct)); }
        catch (Exception ex) { return Result<Order>.Fail(ex); }
    }
}
// Always available — no extra imports needed
var ok  = Result<int>.Ok(42);
var err = Result<int>.Fail(new Exception("oops"));

ok.IsSuccess  // true
ok.Value      // 42
err.IsFailure // true
err.Error     // Exception

// Void methods return Result<Unit>
Result<Unit>.Ok(Unit.Value)

// Two-type variant for typed errors
var r = Result<int, ValidationError>.Ok(42);
var e = Result<int, ValidationError>.Fail(new ValidationError("bad input"));
var result = await service.TryFetchOrderAsync(id)
    .Map(order => order.ToDto())           // transform on success
    .Bind(dto => ValidateDto(dto))         // chain result-returning call
    .Match(
        onSuccess: dto => Ok(dto),         // map to HTTP result
        onFailure: ex  => Problem(ex.Message)
    );

Build-time diagnostics

Misuse is reported by the compiler before it ships to production.

Code Severity Description
AR001 ✖ Error [TryWrap] applied to a non-partial class
AR002 ⚠ Warning [TryWrap] class has no wrappable public methods

How it compares

Source-generated wrappers and auto-injected types without bringing in a runtime result library.

Feature AutoResult.Generator FluentResults OneOf
Compile-time wrapper generation
Zero runtime overhead Minimal Minimal
Core types auto-injected ❌ (install package) ❌ (install package)
AOT-safe
No extra dependency

Also by the same author

More compile-time tooling from Justin Bannister and the Swevo ecosystem.

🌐

Portfolio hub

Explore the full Auto* family and product overview at swevo.github.io.

Visit hub ↗
🧵

AutoWire

Compile-time dependency injection registration with zero reflection.

GitHub ↗
🗺️

AutoMap.Generator

Generate object mapping code at build time. Browse the repo or published docs.

AutoValidate.Generator

Compile-time FluentValidation registration and diagnostics with published docs.

🔎

AutoQuery.Generator

Generate query specifications at compile time for clean LINQ composition.

GitHub ↗
📮

AutoDispatch.Generator

Compile-time CQRS dispatcher generation with strongly typed handlers.

GitHub ↗