PANiXiDA.Core.SpecificationPattern
1.0.2
dotnet add package PANiXiDA.Core.SpecificationPattern --version 1.0.2
NuGet\Install-Package PANiXiDA.Core.SpecificationPattern -Version 1.0.2
<PackageReference Include="PANiXiDA.Core.SpecificationPattern" Version="1.0.2" />
<PackageVersion Include="PANiXiDA.Core.SpecificationPattern" Version="1.0.2" />
<PackageReference Include="PANiXiDA.Core.SpecificationPattern" />
paket add PANiXiDA.Core.SpecificationPattern --version 1.0.2
#r "nuget: PANiXiDA.Core.SpecificationPattern, 1.0.2"
#:package PANiXiDA.Core.SpecificationPattern@1.0.2
#addin nuget:?package=PANiXiDA.Core.SpecificationPattern&version=1.0.2
#tool nuget:?package=PANiXiDA.Core.SpecificationPattern&version=1.0.2
PANiXiDA.Core.SpecificationPattern
PANiXiDA.Core.SpecificationPattern is a .NET library for implementing the Specification pattern with reusable business rules, composable predicates, and filtering support for in-memory collections and query providers.
It is designed for domain and application code that needs explicit, testable rules which can be evaluated against objects or converted to expression trees for querying.
Status
Overview
The package provides a small public API for creating and combining specifications:
- define business rules as
ISpecification<T>orSpecification<T>; - create expression-backed specifications with
SpecificationFactory.Create; - create always-true and always-false specifications with
SpecificationFactory.AllandSpecificationFactory.None; - compose specifications with
And,Or, andNot; - filter
IQueryable<T>sources by expression; - filter
IEnumerable<T>sources by compiled predicate.
Composition implementations are internal. Consumers work through the public abstraction, base class, factory, and extension methods instead of depending on concrete composition classes.
Requirements
- .NET 10 SDK
- A project targeting
net10.0or a compatible target framework
Installation
Package Manager:
dotnet add package PANiXiDA.Core.SpecificationPattern
PackageReference:
<ItemGroup>
<PackageReference Include="PANiXiDA.Core.SpecificationPattern" Version="1.0.1" />
</ItemGroup>
For projects using central package management, define the version in Directory.Packages.props.
<ItemGroup>
<PackageVersion Include="PANiXiDA.Core.SpecificationPattern" Version="1.0.1" />
</ItemGroup>
Quick Start
Create a specification from an expression and use it to evaluate a candidate object:
using PANiXiDA.Core.SpecificationPattern.Core;
using PANiXiDA.Core.SpecificationPattern.Factories;
public sealed class User
{
public bool IsActive { get; init; }
public bool IsBlocked { get; init; }
public int Age { get; init; }
}
Specification<User> activeAdult = SpecificationFactory.Create<User>(
user => user.IsActive && user.Age >= 18);
bool isSatisfied = activeAdult.IsSatisfiedBy(new User
{
IsActive = true,
Age = 21
});
Usage
Custom specifications
Use Specification<T> when a rule deserves a named type:
using System.Linq.Expressions;
using PANiXiDA.Core.SpecificationPattern.Core;
public sealed class ActiveUserSpecification : Specification<User>
{
public override Expression<Func<User, bool>> ToExpression()
{
return user => user.IsActive;
}
}
Named specifications are useful when the same rule is reused across domain logic, application services, and query scenarios.
Composition
Specifications derived from Specification<T> can be combined with And, Or, and Not.
using PANiXiDA.Core.SpecificationPattern.Core;
using PANiXiDA.Core.SpecificationPattern.Factories;
Specification<User> active = new ActiveUserSpecification();
Specification<User> adult = SpecificationFactory.Create<User>(user => user.Age >= 18);
Specification<User> blocked = SpecificationFactory.Create<User>(user => user.IsBlocked);
Specification<User> activeAdult = active.And(adult);
Specification<User> activeOrAdult = active.Or(adult);
Specification<User> allowedActiveAdult = active.And(adult).And(blocked.Not());
And and Or accept ISpecification<T> arguments, so custom implementations can participate in composition. The composition methods themselves are available on Specification<T>.
Queryable filtering
Use the IQueryable<T> extension when the source should receive the expression tree.
using PANiXiDA.Core.SpecificationPattern.Core;
using PANiXiDA.Core.SpecificationPattern.Extensions;
using PANiXiDA.Core.SpecificationPattern.Factories;
using System.Linq;
IQueryable<User> users = new[]
{
new User { IsActive = true, Age = 21 },
new User { IsActive = true, Age = 16 },
new User { IsActive = false, Age = 30 }
}.AsQueryable();
Specification<User> activeAdult = SpecificationFactory
.Create<User>(user => user.IsActive)
.And(SpecificationFactory.Create<User>(user => user.Age >= 18));
IQueryable<User> query = users.Where(activeAdult);
This is intended for query providers such as Entity Framework Core, provided the expression can be translated by the provider.
Enumerable filtering
Use the IEnumerable<T> extension for in-memory collections.
using PANiXiDA.Core.SpecificationPattern.Core;
using PANiXiDA.Core.SpecificationPattern.Extensions;
using PANiXiDA.Core.SpecificationPattern.Factories;
using System.Collections.Generic;
IEnumerable<User> users = new[]
{
new User { IsActive = true, Age = 21 },
new User { IsActive = false, Age = 30 }
};
Specification<User> active = SpecificationFactory.Create<User>(user => user.IsActive);
IEnumerable<User> result = users.Where(active);
For IEnumerable<T>, the specification expression is compiled and evaluated as a predicate.
Public API
ISpecification<T>
Core abstraction for specification implementations.
bool IsSatisfiedBy(T candidate);
Expression<Func<T, bool>> ToExpression();
Specification<T>
Base class for reusable specifications.
- caches the compiled predicate used by
IsSatisfiedBy; - requires derived classes to implement
ToExpression; - exposes
And,Or, andNotcomposition methods.
SpecificationFactory
Factory for common specification creation scenarios.
Specification<T> All<T>();
Specification<T> None<T>();
Specification<T> Create<T>(Expression<Func<T, bool>> expression);
SpecificationQueryableExtensions
Filtering extensions for queryable and enumerable sources.
IQueryable<T> Where<T>(this IQueryable<T> query, ISpecification<T> specification);
IEnumerable<T> Where<T>(this IEnumerable<T> source, ISpecification<T> specification);
Behavior Notes
SpecificationFactory.CreatethrowsArgumentNullExceptionwhenexpressionisnull.Specification<T>.AndandSpecification<T>.OrthrowArgumentNullExceptionwhenspecificationisnull.- Filtering extensions throw
ArgumentNullExceptionwhen the source or specification isnull. Notnegates the current specification.All<T>is satisfied by every candidate.None<T>is not satisfied by any candidate.- Query provider compatibility depends on the expression used by the specification.
Configuration
The package does not require runtime configuration, environment variables, external services, or application settings.
Project Structure
.
|-- src/
| `-- PANiXiDA.Core.SpecificationPattern/
|-- tests/
| `-- PANiXiDA.Core.SpecificationPattern.UnitTests/
|-- Directory.Build.props
|-- Directory.Build.targets
|-- Directory.Packages.props
|-- global.json
|-- version.json
|-- LICENSE
`-- README.md
Development
Restore dependencies:
dotnet restore
Format code:
dotnet format
Build:
dotnet build --configuration Release
Run tests:
dotnet test --configuration Release
Pack:
dotnet pack --configuration Release
Full local validation:
dotnet restore
dotnet format
dotnet build --configuration Release
dotnet test --configuration Release
dotnet pack --configuration Release
Tooling
This repository uses:
- .NET 10
- Nullable reference types
- Implicit usings
- Central package management
- Microsoft Testing Platform
- xUnit v3
- FluentAssertions
- Nerdbank.GitVersioning
Contributing
When changing the package:
- keep the public API small and intentional;
- avoid unnecessary dependencies;
- preserve existing naming and architecture;
- update tests for meaningful behavior changes;
- update this README when public behavior, public API, package metadata, or development workflow changes.
License
This project is licensed under the Apache-2.0 license.
See LICENSE for details.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. 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. |
-
net10.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.2 | 110 | 4/19/2026 |