Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
146 lines (116 sloc) 4.42 KB
using System;
using System.Linq;
using System.Linq.Expressions;
namespace Logic.Movies
{
internal sealed class IdentitySpecification<T> : Specification<T>
{
public override Expression<Func<T, bool>> ToExpression()
{
return x => true;
}
}
public abstract class Specification<T>
{
public static readonly Specification<T> All = new IdentitySpecification<T>();
public bool IsSatisfiedBy(T entity)
{
Func<T, bool> predicate = ToExpression().Compile();
return predicate(entity);
}
public abstract Expression<Func<T, bool>> ToExpression();
public Specification<T> And(Specification<T> specification)
{
if (this == All)
return specification;
if (specification == All)
return this;
return new AndSpecification<T>(this, specification);
}
public Specification<T> Or(Specification<T> specification)
{
if (this == All || specification == All)
return All;
return new OrSpecification<T>(this, specification);
}
public Specification<T> Not()
{
return new NotSpecification<T>(this);
}
}
internal sealed class AndSpecification<T> : Specification<T>
{
private readonly Specification<T> _left;
private readonly Specification<T> _right;
public AndSpecification(Specification<T> left, Specification<T> right)
{
_right = right;
_left = left;
}
public override Expression<Func<T, bool>> ToExpression()
{
Expression<Func<T, bool>> leftExpression = _left.ToExpression();
Expression<Func<T, bool>> rightExpression = _right.ToExpression();
var invokedExpression = Expression.Invoke(rightExpression, leftExpression.Parameters);
return (Expression<Func<T, Boolean>>)Expression.Lambda(Expression.AndAlso(leftExpression.Body, invokedExpression), leftExpression.Parameters);
}
}
internal sealed class OrSpecification<T> : Specification<T>
{
private readonly Specification<T> _left;
private readonly Specification<T> _right;
public OrSpecification(Specification<T> left, Specification<T> right)
{
_right = right;
_left = left;
}
public override Expression<Func<T, bool>> ToExpression()
{
Expression<Func<T, bool>> leftExpression = _left.ToExpression();
Expression<Func<T, bool>> rightExpression = _right.ToExpression();
var invokedExpression = Expression.Invoke(rightExpression, leftExpression.Parameters);
return (Expression<Func<T, Boolean>>)Expression.Lambda(Expression.OrElse(leftExpression.Body, invokedExpression), leftExpression.Parameters);
}
}
internal sealed class NotSpecification<T> : Specification<T>
{
private readonly Specification<T> _specification;
public NotSpecification(Specification<T> specification)
{
_specification = specification;
}
public override Expression<Func<T, bool>> ToExpression()
{
Expression<Func<T, bool>> expression = _specification.ToExpression();
UnaryExpression notExpression = Expression.Not(expression.Body);
return Expression.Lambda<Func<T, bool>>(notExpression, expression.Parameters.Single());
}
}
public sealed class MovieForKidsSpecification : Specification<Movie>
{
public override Expression<Func<Movie, bool>> ToExpression()
{
return movie => movie.MpaaRating <= MpaaRating.PG;
}
}
public sealed class AvailableOnCDSpecification : Specification<Movie>
{
private const int MonthsBeforeDVDIsOut = 6;
public override Expression<Func<Movie, bool>> ToExpression()
{
return movie => movie.ReleaseDate <= DateTime.Now.AddMonths(-MonthsBeforeDVDIsOut);
}
}
public sealed class MovieDirectedBySpecification : Specification<Movie>
{
private readonly string _director;
public MovieDirectedBySpecification(string director)
{
_director = director;
}
public override Expression<Func<Movie, bool>> ToExpression()
{
return movie => movie.Director.Name == _director;
}
}
}
You can’t perform that action at this time.