An expression-based .NET implementation of the specification pattern, providing a framework for defining, combining, and evaluating custom domain-specific specifications.
The specification pattern is a particular software design pattern whereby individual atomic units of business logic can be combined with other units to provide highly maintainable, customizable and readable code.
Background:
The library is extensively documented with XML comments, but the following is a brief overview of the framework itself and how to use it.
Creating specification instances can be done in a few ways:
-
Instantiating the specification class directly
var spec = new MySpecification();
-
Using the
Specify
orSpecify<T>
fluent APISpecification<int> spec1 = Specify.GreaterThan(0);
or
// DateIsLastWeek would be a custom-defined specification
Specification<DateTime> spec2 = Specify<DateTime>.Where<DateIsLastWeek>();
-
Calling composition methods on an existing specification. Note you can use the generic syntax if the spec has a default no-arg constructor, otherwise you must pass an instance in to the composition method.
var composite = spec1.And<MySpec>() .Or<MyOtherSpec>() .And(new AnotherSpec());
Once you have an instance of a specification, applying candidate selection can be done via:
-
Invoking the
IsSatisifedBy()
method directlyif(spec.IsSatisfiedBy(candidate)) DoSomething();
-
Invoking one of the
Filter()
overloads and passing in a collectionvar matches = spec.Filter(collection);
-
Passing the specification to a LINQ query using one of the
Matching<T>()
extension method overloadsvar query1 = collection.Matching(spec);
Custom specifications can be created in the following manners:
-
Ad-hoc by using
Specify<T>.Where(Expression<Func<T, bool>>)
and supplying a lambda expressionvar intGreaterThanZero = Specify<int>.Where(i => i > 0);
-
Deriving from
Specification<T>
and implementing theBuildCriteria()
method by returning a lambda expressionpublic class IntegerGreaterThanZero : Specification<int> { protected override Expression<Func<int, bool>> BuildCriteria() { return x => x > 0; } }
-
Deriving from
CompositeSpecification<T>
and implementing theBuildComposite()
method by returning a composite specification instance.public class IntegerComposite : CompositeSpecification<int> { protected override Specification<int> BuildComposite() { return Specify<int> .Where<IntegerGreaterThanZero>() .Or<IntegerEqualToZero>() .AndNot<IntegerLessThanZero>(); } }
-
Finish Subsumption and Partial Fulfillment aspects
-
Improve the fluent API a bit, it still seems klunky in some respects.