Skip to content

Specification Pattern

A practical guide to implementing composable business rules with C# Functorium


If your Repository methods keep growing endlessly and business rules are scattered throughout your service code, the Specification pattern may be the answer.

This tutorial is a comprehensive course designed for step-by-step learning of domain rule implementation using the Specification pattern. From a basic Specification class to Expression Tree-based Repository integration, you will systematically learn every aspect of the Specification pattern through 18 hands-on projects.

Experience the journey from simple conditional branching to composable business rules.

LevelAudienceRecommended Scope
BeginnerDevelopers who know basic C# syntax and want to get started with the Specification patternPart 1
IntermediateDevelopers who understand the pattern and want practical applicationParts 1—3
AdvancedDevelopers interested in architecture design and domain modelingParts 4—5 + Appendix

After completing this tutorial, you will be able to:

  1. Understand and explain the concept and necessity of the Specification pattern
  2. Implement complex business rules using And, Or, Not composition
  3. Implement ORM-compatible Specifications using Expression Trees
  4. Build flexible data retrieval through Repository and Specification integration
  5. Apply testing strategies for reliable domain rule verification

The introduction covers the Specification pattern concept and environment setup.

Learn from basic Specifications through operator overloading to the identity element.

ChTopicKey Learning
1First SpecificationInheriting Specification, implementing IsSatisfiedBy
2CompositionAnd, Or, Not method composition
3Operators&,
4All Identity ElementAll identity element, dynamic filter chaining

Prepare for ORM integration with Expression Tree-based Specifications.

ChTopicKey Learning
1Expression IntroductionExpression Tree concept and necessity
2ExpressionSpecification Classsealed IsSatisfiedBy, delegate caching
3Value Object Conversion PatternValue Object to primitive conversion
4Expression ResolverTryResolve, recursive composition

Integrate Specifications with Repositories for flexible data retrieval.

ChTopicKey Learning
1Repository with SpecificationPreventing Repository method explosion
2InMemory ImplementationInMemory adapter
3PropertyMapPropertyMap, TranslatingVisitor
4EF Core ImplementationTryResolve + Translate combination

Learn how to use the Specification pattern in production projects.

ChTopicKey Learning
1Use-Case PatternsUsing Specs with CQRS
2Dynamic Filter BuilderAll seed conditional chaining
3Testing StrategiesSpec/composition/use-case testing
4Architecture RulesNaming, folder placement, ArchUnitNET

Part 5: Domain-Specific Practical Examples

Section titled “Part 5: Domain-Specific Practical Examples”

Practical examples applying the Specification pattern across various domains.


Part 1
Ch 1: First Spec -> Ch 2: And/Or/Not Composition -> Ch 3: Operator Overloading -> Ch 4: All Identity Element
Part 2
Ch 1: Expression Intro -> Ch 2: ExpressionSpec -> Ch 3: VO Conversion Pattern -> Ch 4: Expression Resolver
Part 3
Ch 1: Repository Integration -> Ch 2: InMemory Implementation -> Ch 3: PropertyMap -> Ch 4: EF Core Implementation
Part 4
Ch 1: Use-Case Patterns -> Ch 2: Dynamic Filter -> Ch 3: Testing Strategies -> Ch 4: Architecture Rules

The core type hierarchy covered in this tutorial is as follows.

Specification<T> (abstract class)
├── IsSatisfiedBy(T) : bool
├── And() / Or() / Not()
├── & / | / ! operators
└── All (identity element)
IExpressionSpec<T> (interface)
└── ToExpression() : Expression<Func<T, bool>>
ExpressionSpecification<T> : Specification<T>, IExpressionSpec<T>
├── abstract ToExpression()
├── sealed IsSatisfiedBy (compilation + caching)
└── AllSpecification<T> (internal, identity element: _ => true)
SpecificationExpressionResolver (Expression composition)
PropertyMap<TEntity, TModel> (Entity→Model conversion)

  • .NET 10.0 SDK or later
  • VS Code + C# Dev Kit extension
  • Basic knowledge of C# syntax

specification-pattern/
├── Part0-Introduction/ # Part 0: Introduction
├── Part1-Specification-Basics/ # Part 1: Specification Basics (4)
│ ├── 01-First-Specification/
│ ├── 02-Composition/
│ ├── 03-Operators/
│ └── 04-All-Identity/
├── Part2-Expression-Specification/ # Part 2: Expression Specification (4)
│ ├── 01-Expression-Introduction/
│ ├── 02-ExpressionSpecification-Class/
│ ├── 03-ValueObject-Primitive-Conversion/
│ └── 04-Expression-Resolver/
├── Part3-Repository-Integration/ # Part 3: Repository Integration (4)
│ ├── 01-Repository-With-Specification/
│ ├── 02-InMemory-Implementation/
│ ├── 03-PropertyMap/
│ └── 04-EfCore-Implementation/
├── Part4-Real-World-Patterns/ # Part 4: Real-World Patterns (4)
│ ├── 01-Usecase-Patterns/
│ ├── 02-Dynamic-Filter-Builder/
│ ├── 03-Testing-Strategies/
│ └── 04-Architecture-Rules/
├── Part5-Domain-Examples/ # Part 5: Domain-Specific Practical Examples (2)
│ ├── 01-Ecommerce-Product-Filtering/
│ └── 02-Customer-Management/
├── Appendix/ # Appendix
└── index.md # This document

All example projects in every Part include unit tests. Tests follow the Unit Testing Guide.

Terminal window
# Build the entire tutorial
dotnet build specification-pattern.slnx
# Test the entire tutorial
dotnet test --solution specification-pattern.slnx

Part 1: Specification Basics (4)

ChTest ProjectKey Test Content
1FirstSpecification.Tests.UnitIsSatisfiedBy behavior verification
2Composition.Tests.UnitAnd, Or, Not composition verification
3Operators.Tests.UnitOperator overloading verification
4AllIdentity.Tests.UnitAll identity element, dynamic chaining

Part 2: Expression Specification (4)

ChTest ProjectKey Test Content
1ExpressionIntro.Tests.UnitExpression Tree basics
2ExpressionSpec.Tests.Unitsealed IsSatisfiedBy, caching
3ValueObjectConversion.Tests.UnitVO to primitive conversion
4ExpressionResolver.Tests.UnitTryResolve, recursive composition

Part 3: Repository Integration (4)

ChTest ProjectKey Test Content
1RepositorySpec.Tests.UnitRepository + Spec integration
2InMemoryImpl.Tests.UnitInMemory adapter
3PropertyMapDemo.Tests.UnitPropertyMap, TranslatingVisitor
4EfCoreImpl.Tests.UnitEF Core TryResolve + Translate

Part 4: Real-World Patterns (4)

ChTest ProjectKey Test Content
1UsecasePatterns.Tests.UnitCQRS + Spec usage
2DynamicFilter.Tests.UnitDynamic filter chaining
3TestingStrategies.Tests.UnitSpec testing patterns
4ArchitectureRules.Tests.UnitArchitecture rule verification

Part 5: Domain-Specific Practical Examples (2)

ChTest ProjectKey Test Content
1EcommerceFiltering.Tests.UnitProduct filtering Spec
2CustomerManagement.Tests.UnitCustomer management Spec

Follows the T1_T2_T3 naming convention:

// Method_ExpectedResult_Scenario
[Fact]
public void IsSatisfiedBy_ReturnsTrue_WhenProductIsActive()
{
// Arrange
var spec = new ActiveProductSpec();
var product = new Product { IsActive = true };
// Act
var actual = spec.IsSatisfiedBy(product);
// Assert
actual.ShouldBeTrue();
}

All example code for this tutorial can be found in the Functorium project:

  • Framework types: Src/Functorium/Domains/Specifications/
  • Tutorial projects: Docs.Site/src/content/docs/tutorials/specification-pattern/

This tutorial is more effective when studied together with:


This tutorial was written based on real-world experience developing the Specification framework in the Functorium project.