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.

public static class SpecificationExtensions {
        public static ISpecification< T > And< T >( this ISpecification< T > leftSide, ISpecification< T > rightSide ) {
            return new AndSpecification< T >( leftSide, rightSide );
        }

        public static ISpecification< T > And< T >( this ISpecification< T > left, Predicate< T > criteriaToSatisfy ) {
            return left.And( new Specification< T >( criteriaToSatisfy ) );
        }

        public static ISpecification< T > Or< T >( this ISpecification< T > leftSide, ISpecification< T > rightSide ) {
            return new OrSpecification< T >( leftSide, rightSide );
        }

        public static ISpecification< T > Or< T >( this ISpecification< T > left, Predicate< T > criteriaToSatisfy ) {
            return left.Or( new Specification< T >( criteriaToSatisfy ) );
        }

        private class AndSpecification< T > : ISpecification< T > {
            public AndSpecification( ISpecification< T > leftCriteria, ISpecification< T > rightCriteria ) {
                this.leftCriteria = leftCriteria;
                this.rightCriteria = rightCriteria;
            }

            public bool IsSatisfiedBy( T item ) {
                return leftCriteria.IsSatisfiedBy( item ) && rightCriteria.IsSatisfiedBy( item );
            }

            private ISpecification< T > leftCriteria;
            private ISpecification< T > rightCriteria;
        }

        private class OrSpecification< T > : ISpecification< T > {
            public OrSpecification( ISpecification< T > leftCriteria, ISpecification< T > rightCriteria ) {
                this.leftCriteria = leftCriteria;
                this.rightCriteria = rightCriteria;
            }

            public bool IsSatisfiedBy( T item ) {
                return leftCriteria.IsSatisfiedBy( item ) || rightCriteria.IsSatisfiedBy( item );
            }

            private ISpecification< T > leftCriteria;
            private ISpecification< T > rightCriteria;
        }
    }

By accepting a Predicate delegate as the second argument you can now inline your lambdas and still take advantage of specifications. Client components can now take advantage of these extensions like this...

public class SlipsRepository : ISlipsRepository {
        public SlipsRepository( ISlipDataMapper mapper ) {
            _mapper = mapper;
        }

        public IEnumerable< ISlip > AllAvailableSlips() {
            return _mapper.AllSlips( ).Where( Is.NotLeased( ) );
        }

        public IEnumerable< ISlip > AllAvailableSlipsFor( IDock dockToFindSlipsOn ) {
            return _mapper.AllSlips( ).Where( Is.NotLeased( ).And( Is.On( dockToFindSlipsOn ) ) );
        }

        private readonly ISlipDataMapper _mapper;

        private static class Is {
            public static ISpecification< ISlip > NotLeased() {
                return new Specification< ISlip >( slip => !slip.IsLeased( ) );
            }

            public static Predicate< ISlip > On( IDock dock ) {
                return slip => dock.Equals( slip.Dock( ) );
            }
        }
    }

The base specification class becomes a quick and easy…

public class Specification< T > : ISpecification< T > {
        public Specification( Predicate< T > criteriaToSatisfy ) {
            _criteriaToSatisfy = criteriaToSatisfy;
        }

        public bool IsSatisfiedBy( T item ) {
            return _criteriaToSatisfy( item );
        }

        private readonly Predicate< T > _criteriaToSatisfy;
    }
comments powered by Disqus