Specifications & Extension Methods Posted on March 06, 2008 @ 12:56 csharp
Last week I went and checked out JP's latest presentation on Generics at the Calgary .NET User Group, and as usual it was awesome! He's definitely knee deep in C# 3.0, and was dropping lambda's and extension methods like it was old news... Here's some of the stuff I learned.
Extending the ISpecification interface via the use of Extension methods.
1 public static class SpecificationExtensions {
2 public static ISpecification< T > And< T >( this ISpecification< T > leftSide, ISpecification< T > rightSide ) {
3 return new AndSpecification< T >( leftSide, rightSide );
4 }
5
6 public static ISpecification< T > And< T >( this ISpecification< T > left, Predicate< T > criteriaToSatisfy ) {
7 return left.And( new Specification< T >( criteriaToSatisfy ) );
8 }
9
10 public static ISpecification< T > Or< T >( this ISpecification< T > leftSide, ISpecification< T > rightSide ) {
11 return new OrSpecification< T >( leftSide, rightSide );
12 }
13
14 public static ISpecification< T > Or< T >( this ISpecification< T > left, Predicate< T > criteriaToSatisfy ) {
15 return left.Or( new Specification< T >( criteriaToSatisfy ) );
16 }
17
18 private class AndSpecification< T > : ISpecification< T > {
19 public AndSpecification( ISpecification< T > leftCriteria, ISpecification< T > rightCriteria ) {
20 this.leftCriteria = leftCriteria;
21 this.rightCriteria = rightCriteria;
22 }
23
24 public bool IsSatisfiedBy( T item ) {
25 return leftCriteria.IsSatisfiedBy( item ) && rightCriteria.IsSatisfiedBy( item );
26 }
27
28 private ISpecification< T > leftCriteria;
29 private ISpecification< T > rightCriteria;
30 }
31
32 private class OrSpecification< T > : ISpecification< T > {
33 public OrSpecification( ISpecification< T > leftCriteria, ISpecification< T > rightCriteria ) {
34 this.leftCriteria = leftCriteria;
35 this.rightCriteria = rightCriteria;
36 }
37
38 public bool IsSatisfiedBy( T item ) {
39 return leftCriteria.IsSatisfiedBy( item ) || rightCriteria.IsSatisfiedBy( item );
40 }
41
42 private ISpecification< T > leftCriteria;
43 private ISpecification< T > rightCriteria;
44 }
45 }
By accepting a Predicate
1 public class SlipsRepository : ISlipsRepository {
2 public SlipsRepository( ISlipDataMapper mapper ) {
3 _mapper = mapper;
4 }
5
6 public IEnumerable< ISlip > AllAvailableSlips() {
7 return _mapper.AllSlips( ).Where( Is.NotLeased( ) );
8 }
9
10 public IEnumerable< ISlip > AllAvailableSlipsFor( IDock dockToFindSlipsOn ) {
11 return _mapper.AllSlips( ).Where( Is.NotLeased( ).And( Is.On( dockToFindSlipsOn ) ) );
12 }
13
14 private readonly ISlipDataMapper _mapper;
15
16 private static class Is {
17 public static ISpecification< ISlip > NotLeased() {
18 return new Specification< ISlip >( slip => !slip.IsLeased( ) );
19 }
20
21 public static Predicate< ISlip > On( IDock dock ) {
22 return slip => dock.Equals( slip.Dock( ) );
23 }
24 }
25 }
The base specification class becomes a quick and easy...
1 public class Specification< T > : ISpecification< T > {
2 public Specification( Predicate< T > criteriaToSatisfy ) {
3 _criteriaToSatisfy = criteriaToSatisfy;
4 }
5
6 public bool IsSatisfiedBy( T item ) {
7 return _criteriaToSatisfy( item );
8 }
9
10 private readonly Predicate< T > _criteriaToSatisfy;
11 }