ZeroAlloc.Specification
1.2.3
dotnet add package ZeroAlloc.Specification --version 1.2.3
NuGet\Install-Package ZeroAlloc.Specification -Version 1.2.3
<PackageReference Include="ZeroAlloc.Specification" Version="1.2.3" />
<PackageVersion Include="ZeroAlloc.Specification" Version="1.2.3" />
<PackageReference Include="ZeroAlloc.Specification" />
paket add ZeroAlloc.Specification --version 1.2.3
#r "nuget: ZeroAlloc.Specification, 1.2.3"
#:package ZeroAlloc.Specification@1.2.3
#addin nuget:?package=ZeroAlloc.Specification&version=1.2.3
#tool nuget:?package=ZeroAlloc.Specification&version=1.2.3
ZeroAlloc.Specification
Source-generated, zero-allocation specification pattern for .NET 8+.
Multiple packages in this family — see Documentation or NuGet for the full list.
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
[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 8.0 (the de-facto specification library in .NET). .NET 10.0.7, i9-12900HK, BenchmarkDotNet v0.15.4.
| Operation | Ardalis.Specification | ZA.Specification | Speedup |
|---|---|---|---|
| Construct composed spec | 1,719 ns / 1,248 B | 40 ns / 24 B | 43× faster, 52× less alloc |
| Compose two specs | 3,959 ns / 2,648 B | 22 ns / 24 B | 180× faster, 110× less alloc |
| Evaluate over 100 items (in-memory) | 170,862 ns / 4,688 B | 150 ns / 0 B | 1,136× faster, 0 B alloc |
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–ZA004 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–ZA004 compile-time errors 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.