ZeroAlloc.Specification 1.3.3

dotnet add package ZeroAlloc.Specification --version 1.3.3
                    
NuGet\Install-Package ZeroAlloc.Specification -Version 1.3.3
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="ZeroAlloc.Specification" Version="1.3.3" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="ZeroAlloc.Specification" Version="1.3.3" />
                    
Directory.Packages.props
<PackageReference Include="ZeroAlloc.Specification" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add ZeroAlloc.Specification --version 1.3.3
                    
#r "nuget: ZeroAlloc.Specification, 1.3.3"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package ZeroAlloc.Specification@1.3.3
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=ZeroAlloc.Specification&version=1.3.3
                    
Install as a Cake Addin
#tool nuget:?package=ZeroAlloc.Specification&version=1.3.3
                    
Install as a Cake Tool

ZeroAlloc.Specification

NuGet Build codecov License: MIT AOT GitHub Sponsors

Source-generated specification pattern for .NET, an Ardalis.Specification alternative: specs are structs, so composing and evaluating them allocates nothing, and the same spec still translates to SQL through EF Core.

Why ZeroAlloc.Specification

  • Composing and evaluating allocates nothing. And, Or and Not build readonly struct values. Composing and calling IsSatisfiedBy allocates 0 B, asserted by tests. Ardalis.Specification allocates 1,752 B to compose two specs.
  • About 630× faster for in-memory filtering than Ardalis.Specification, measured in the same run over 100 items, because nothing is compiled per call, and it allocates nothing against 4,743 B.
  • One spec for memory and the database. Every spec also exposes ToExpression(), so EF Core turns the composed spec into a WHERE clause.
  • Works under NativeAOT and trimming, with a NativeAOT smoke app published and run in CI. Mistakes such as [Specification] on a class or a missing partial are compile errors ZA001 to ZA003.

Install

dotnet add package ZeroAlloc.Specification

The source generator ships inside this package. Targets .NET 8 and later.

Quick start

using System.Linq.Expressions;
using ZeroAlloc.Specification;

User[] users = [new("Ann", true, 1500m), new("Bob", true, 200m), new("Cy", false, 3000m)];

var spec = new ActiveUserSpec().And(new BigSpenderSpec(1000m));        // a struct, 0 B

Console.WriteLine(users.Count(u => spec.IsSatisfiedBy(u)));             // 1, in memory
Console.WriteLine(spec.ToExpression());   // one combined expression for dbContext.Users.Where(...)

public sealed record User(string Name, bool IsActive, decimal TotalSpend);

[Specification]
public readonly partial struct ActiveUserSpec : ISpecification<User>
{
    public bool IsSatisfiedBy(User user) => user.IsActive;
    public Expression<Func<User, bool>> ToExpression() => u => u.IsActive;
}

[Specification]
public readonly partial struct BigSpenderSpec(decimal minSpend) : ISpecification<User>
{
    public bool IsSatisfiedBy(User user) => user.TotalSpend >= minSpend;
    public Expression<Func<User, bool>> ToExpression() { var min = minSpend; return u => u.TotalSpend >= min; }
}

The generator adds And, Or and Not to every [Specification] struct. Evaluation is a direct call on a struct that the JIT can inline, with no virtual dispatch.

What you get

  • Fluent composition: And, Or and Not, nested to any depth, without allocating.
  • Static builder: Spec.And, Spec.Or and Spec.Not when you want explicit type arguments.
  • In-memory evaluation through IsSatisfiedBy, for hot loops and domain rules.
  • EF Core translation through ToExpression(), which combines the specs' expression trees into one.
  • Compile-time checks that each spec is a readonly partial struct implementing ISpecification<T>.
  • Recipes for an EF Core repository, complex compositions and caching the expression of a stateless spec.

Building an expression tree with ToExpression() does allocate, as every expression tree does. Cache it for stateless specs.

Performance

Head-to-head vs Ardalis.Specification 9.3.1, .NET 10.0.13, BenchmarkDotNet v0.15.8. Allocations are exact; speed is a same-run ratio.

Operation Ardalis.Specification time ÷ ZA's Ardalis alloc ZA alloc
Construct composed spec ZA below resolution 792 B 0 B
Compose two specs ZA below resolution 1,752 B 0 B
Evaluate over 100 items (in-memory) 630× (632–633) 4,743 B 0 B

ZA's construct and compose are below what BenchmarkDotNet can tell apart from an empty method, so no finite ratio can be given for them. For database queries the SQL provider dominates and the gap is invisible; for in-memory filtering it dominates. Full methodology: docs/performance.md.

Learn more

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net8.0

    • No dependencies.

NuGet packages (2)

Showing the top 2 NuGet packages that depend on ZeroAlloc.Specification:

Package Downloads
Rag.NET.Abstractions

Interfaces and models for the Rag.NET library

Rag.NET

Modular RAG pipeline library for .NET — ingestion and retrieval pipeline builders, self-query, corrective RAG and conversation memory

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.3.3 46 10/21/2026
1.3.2 1,677 10/16/2026
1.3.1 91 10/15/2026
1.3.0 709 10/10/2026
1.2.5 106 9/30/2026
1.2.4 145 9/26/2026
1.2.3 1,385 9/20/2026
1.2.2 215 9/20/2026
1.2.1 105 9/20/2026
1.2.0 111 9/19/2026
1.1.0 2,273 5/4/2026
0.1.0 148 3/18/2026