Skip to content

All Identity Element

Specification<T>.All is a special Specification that satisfies all entities. In this chapter, you will learn how All serves as the identity element of the AND operation and how it makes dynamic filter construction concise.

All & X == X — Like 1 * x == x in mathematics, All is a neutral element that has no effect in AND operations.

  1. Understanding the Null Object Pattern

    • All is a Null Object representing “no conditions”
    • Start with All instead of null checks to safely accumulate conditions
  2. Identity Element Concept

    • All & X == X, X & All == X (identity element of AND operation)
    • When the & operator detects All, it returns the other operand as-is without creating a new object
  3. Dynamic Filter Pattern

    • Incrementally assembling Specifications based on user input or search criteria
    • Pattern of starting with All and adding conditions with &=
  • All.IsSatisfiedBy() always returns true
  • All & X returns the same reference as X (ReferenceEquals)
  • Dynamic filter construction and execution

When representing “no conditions” in programming, null is commonly used:

// Using null - null check required every time
Specification<Product>? spec = null;
if (hasCategory)
spec = spec == null ? new ProductCategorySpec(cat) : spec.And(new ProductCategorySpec(cat));
if (hasPrice)
spec = spec == null ? new ProductPriceRangeSpec(min, max) : spec.And(new ProductPriceRangeSpec(min, max));
// Null check also required at execution time
var results = spec == null ? products : products.Where(p => spec.IsSatisfiedBy(p));

Using All eliminates null checks:

// Using All - no null checks needed
var spec = Specification<Product>.All;
if (hasCategory)
spec &= new ProductCategorySpec(cat);
if (hasPrice)
spec &= new ProductPriceRangeSpec(min, max);
// Execution - All returns all products, conditions apply filtering
var results = products.Where(p => spec.IsSatisfiedBy(p));

Reference Optimization of the Identity Element

Section titled “Reference Optimization of the Identity Element”

The & operator detects All and returns the other operand as-is without creating a new object:

var all = Specification<Product>.All;
var inStock = new ProductInStockSpec();
var result = all & inStock;
ReferenceEquals(result, inStock); // true - not a new object!

This is not merely an optimization but a code expression of the mathematical definition of an identity element. Just as 1 * x == x in multiplication, All & X == X in AND operations.

This is the most commonly used pattern in practice. When only user-selected conditions on a search screen need to be applied:

var spec = Specification<Product>.All;
if (categoryFilter is not null)
spec &= new ProductCategorySpec(categoryFilter);
if (nameFilter is not null)
spec &= new ProductNameContainsSpec(nameFilter);
if (onlyInStock)
spec &= new ProductInStockSpec();
var results = products.Where(p => spec.IsSatisfiedBy(p));

If no conditions are selected, spec remains All, so all products are returned.

AllIdentity/
├── Program.cs
├── Product.cs
├── SampleProducts.cs
├── Specifications/
│ ├── ProductInStockSpec.cs
│ ├── ProductPriceRangeSpec.cs
│ ├── ProductCategorySpec.cs
│ └── ProductNameContainsSpec.cs
└── AllIdentity.csproj
AllIdentity.Tests.Unit/
├── AllIdentityTests.cs
├── Using.cs
├── xunit.runner.json
└── AllIdentity.Tests.Unit.csproj
var spec = Specification<Product>.All;
if (categoryFilter is not null)
spec &= new ProductCategorySpec(categoryFilter);
if (onlyInStock)
spec &= new ProductInStockSpec();
var results = SampleProducts.All.Where(p => spec.IsSatisfiedBy(p));
PropertyValue/Behavior
All.IsSatisfiedBy(x)Always true
All.IsAlltrue
All & XReturns X (ReferenceEquals)
X & AllReturns X (ReferenceEquals)
Aspectnull ApproachAll Approach
Initial ValuenullSpecification<T>.All
Adding ConditionsNull check then And or assign&= operator
ExecutionNull check then filter or return allJust filter (All returns everything)
SafetyNullReferenceException risknull-safe

A: Yes, AllSpecification<T> is implemented as a per-type singleton through a static readonly instance. Specification<Product>.All always returns the same object.

A: Technically possible, but the semantics are different. All | X is always true (since All satisfies everything), making it effectively the same as All. All is designed as the identity element of the AND operation; in Or operations, it becomes an absorbing element.

Q3: Why doesn’t the And() method have identity element optimization?

Section titled “Q3: Why doesn’t the And() method have identity element optimization?”

A: The And() method simply returns new AndSpecification<T>(this, other). The identity element optimization is only included in the & operator. This is a design decision to maintain the simplicity of the method while ensuring performance and reference equality when using operators.

Q4: Can Or conditions also be added in dynamic filters?

Section titled “Q4: Can Or conditions also be added in dynamic filters?”

A: Yes, you can use the |= operator. However, when mixing And and Or, be careful about operator precedence. If complex compositions are needed, it is better to clarify intent using intermediate variables.

A: It is used everywhere that requires dynamically constructing queries based on user input, such as search APIs, filtering UIs, and report conditions. In Part 3, you will learn how to generate dynamic SQL queries by combining this with EF Core.


In Part 1, we built the foundations of Specification — condition encapsulation, composition, operators, and the All identity element. However, the Specifications so far only work on in-memory collections. In Part 2, we introduce Expression Trees to make Specifications usable with ORMs like EF Core.

-> Part 2 Chapter 1: Introduction to Expressions