ZeroAlloc.Specification
1.3.1
See the version list below for details.
dotnet add package ZeroAlloc.Specification --version 1.3.1
NuGet\Install-Package ZeroAlloc.Specification -Version 1.3.1
<PackageReference Include="ZeroAlloc.Specification" Version="1.3.1" />
<PackageVersion Include="ZeroAlloc.Specification" Version="1.3.1" />
<PackageReference Include="ZeroAlloc.Specification" />
paket add ZeroAlloc.Specification --version 1.3.1
#r "nuget: ZeroAlloc.Specification, 1.3.1"
#:package ZeroAlloc.Specification@1.3.1
#addin nuget:?package=ZeroAlloc.Specification&version=1.3.1
#tool nuget:?package=ZeroAlloc.Specification&version=1.3.1
ZeroAlloc.Specification
Source-generated, zero-allocation specification pattern for .NET 8+.
Install
The source generator is bundled into the main package — a single PackageReference is all you need:
dotnet add package ZeroAlloc.Specification
The standalone
ZeroAlloc.Specification.Generatorpackage is still published for backwards compatibility with existing direct PackageReferences, but new consumers should reference onlyZeroAlloc.Specification.
Example
using System.Linq.Expressions;
using ZeroAlloc.Specification;
[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 PremiumUserSpec : ISpecification<User>
{
private readonly decimal _minSpend;
public PremiumUserSpec(decimal minSpend) => _minSpend = minSpend;
public bool IsSatisfiedBy(User user) => user.TotalSpend >= _minSpend;
public Expression<Func<User, bool>> ToExpression()
{
var min = _minSpend;
return u => u.TotalSpend >= min;
}
}
// Fluent composition — zero allocation
var spec = new ActiveUserSpec().And(new PremiumUserSpec(1000m));
// In-memory
bool result = spec.IsSatisfiedBy(user);
// EF Core — translates to SQL
var users = await dbContext.Users.Where(spec.ToExpression()).ToListAsync();
Performance
Head-to-head vs Ardalis.Specification 9.3.1 (the de-facto specification library in .NET). .NET 10.0.13, Intel Core Ultra 7 255H, BenchmarkDotNet v0.15.8.
| Operation | Ardalis.Specification | ZA.Specification | Speedup |
|---|---|---|---|
| Construct composed spec | 305 ns / 792 B | < 1 ns / 0 B | > 300× faster, 0 B alloc |
| Compose two specs | 821 ns / 1,752 B | < 1 ns / 0 B | > 800× faster, 0 B alloc |
| Evaluate over 100 items (in-memory) | 15,599 ns / 4,743 B | 49 ns / 0 B | ~320× faster, 0 B alloc |
Rows under 1 ns are below what BenchmarkDotNet can tell apart from an empty method: the JIT reduces building two empty structs to nothing, so those speedups are lower bounds. The machine was shared while measuring, so timings are approximate; the allocations are exact.
The in-memory-evaluation gap is dramatic because Ardalis pays Expression.Compile() per call. For EF Core / database queries the SQL provider dominates and the overhead is invisible; for in-memory filtering it dominates.
Full methodology + analysis: docs/performance.md.
Features
- Zero allocations — composed specs are
readonly structvalues, not heap objects - EF Core compatible — every spec exposes
ToExpression()returningExpression<Func<T, bool>> - Source-generated fluent API —
And<TOther>(),Or<TOther>(),Not()added by Roslyn generator - Static builder —
Spec.And(),Spec.Or(),Spec.Not()for explicit type arguments - Compile-time safety — ZA001–ZA005 diagnostics enforce correct
partial structusage - .NET 8+, C# 12
Documentation
| Page | Description |
|---|---|
| Introduction | What it is and why it exists |
| Getting Started | Install and first specification in 5 minutes |
| Core Concepts | ISpecification<T>, structs, stateful vs stateless |
| Fluent API | Generated And/Or/Not methods |
| Static Builder | Spec.And/Or/Not |
| Expression Composition | ToExpression() and EF Core translation |
| Diagnostics | ZA001–ZA005 compile-time diagnostics and fixes |
| Generator Internals | How the Roslyn generator works |
| Performance | Allocation comparison and benchmarks |
| Cookbook: EF Core Repository | Repository pattern integration |
| Cookbook: Combining Specs | Complex compositions |
| Cookbook: Stateless Caching | Cache expression trees for stateless specs |
License
MIT — see LICENSE.
| Product | Versions 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. |
-
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.