Skip to main content
net8.0net9.0net10.0

A zero-allocation, no-boxing Result<T,E> library for .NET with full CSharpFunctionalExtensions API parity.

Published
Mar 19, 2026
7mo ago
Total Downloads
59.6K
59,564

Install

dotnet add package ZeroAlloc.Results --version 0.1.3
ProductVersions
.NET
net10.0net8.0net9.0

README

ZeroAlloc.Results

NuGet Build License: MIT

ZeroAlloc.Results is a zero-allocation, no-boxing Result<T, E> library for .NET 9. All types are readonly struct — no heap allocation, no boxing, no GC pressure.

Install

dotnet add package ZeroAlloc.Results

Quick Example

using ZeroAlloc.Results;
using ZeroAlloc.Results.Extensions;

// Create
Result<int, string> ok = Result<int, string>.Success(42);
Result<int, string> fail = Result<int, string>.Failure("not found");

// Or via implicit conversion
Result<int, string> r = 42;       // success
Result<int, string> e = "error";  // failure

// Chain with Map, Bind, Ensure
var result = GetUser(id)
    .Ensure(u => u.IsActive, "user is inactive")
    .Map(u => u.Email)
    .Bind(email => SendWelcome(email));

// Match to extract
string message = result.Match(
    onSuccess: email => $"Sent to {email}",
    onFailure: err  => $"Failed: {err}");

// LINQ query syntax
var greeting =
    from user    in GetUser(id)
    from profile in GetProfile(user)
    select $"Hello, {profile.Name}";

// Async pipelines with ValueTask
var response = await GetUser(id)
    .MapAsync(async u  => await LoadPermissions(u))
    .BindAsync(async p => await BuildToken(p));

Types

Type Success Error Use case
Result — string simple pass/fail
Result<T> T string most common
Result<T, E> T E fully generic
UnitResult<E> — E typed error, no value
Maybe<T> T — optional value

API

Method Description
Map(T→U) Transform the success value
MapError(E→F) Transform the error value
Bind(T→Result<U,E>) Chain result-returning functions
Match(onSuccess, onFailure) Extract a value from either branch
Tap(T→void) Side-effect on success, pass through
TapError(E→void) Side-effect on failure, pass through
Ensure(T→bool, E) Validate success value
Combine(Span<Result<T,E>>) Merge multiple results, zero-alloc
*Async ValueTask-based variant of each combinator

Performance

All core operations produce zero heap allocations (Windows 11, .NET 9.0.14, BenchmarkDotNet v0.13.12).

Method Mean Allocated
Result<int,string>.Success(42) 0.25 ns 0 B
Result<int,string>.Failure("err") 0.43 ns 0 B
.Map(x => x * 2) 2.92 ns 0 B
.Bind(x => Success(x.ToString())) 8.81 ns 0 B
.Match(v => v, _ => -1) 2.02 ns 0 B
Maybe<int>.Some(42) 3.66 ns 0 B
UnitResult<string>.Success() 0.35 ns 0 B

Head-to-head vs CSharpFunctionalExtensions 3.7.0 (Windows 11, .NET 9.0.14, BenchmarkDotNet v0.13.12):

Category ZeroAlloc.Results CSharpFunctionalExtensions Allocated Ratio
Create_Success 0.33 ns 2.89 ns 0 B both 8.7× faster
Create_Failure 0.30 ns 1.44 ns 0 B both 4.8× faster
Map 1.09 ns 1.48 ns 0 B both 1.4× faster
Match 0.37 ns 0.68 ns 0 B both 1.9× faster
Chain (Map+Bind+Match) 2.28 ns 2.45 ns 0 B both 1.1× faster

See docs/performance.md for the full benchmark analysis and zero-allocation design explanation.

Documentation

Page Description
Getting Started Install and write your first result pipeline
Types All five result types and when to use each
Combinators Map, Bind, Match, Tap, Ensure, Combine
Async ValueTask async variants for all combinators
LINQ Query syntax with Select and SelectMany
Performance Zero-alloc design and benchmark results

License

MIT

Changes from Previous Version

No structural changes between v0.1.2 and v0.1.3.

Adoption Assessment

Assess this package against its supported frameworks, license, maintenance signals and dependency graph before making it a project standard.

Compatibility metadata lists 3 target frameworks; confirm the exact target used by your application.

Related Guides & Workflows

Learn how to evaluate, integrate, or audit this package in your .NET project.