Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
composed spec - parameter replacement (#1)
* composed spec - parameter replacement Fixes invalid op exception when composing specs. * connection string back to . Sorry -- forgot to remove my connection string and put yours back in.
- Loading branch information
1 parent
bcf120e
commit 1508638
Showing
6 changed files
with
69 additions
and
31 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
using Should; | ||
using Xunit; | ||
|
||
namespace SpecificationPattern.Tests { | ||
|
||
public class ComposedSpecificationTests { | ||
|
||
[Fact] | ||
public void T1() { | ||
var movie = new Movie("Some Movie", new DateTime(2010, 2, 1), MpaaRating.G, "Triller", 10); | ||
var pg13Rating = new MpaaRatingAtMostSpecification(MpaaRating.PG13); | ||
var goodMovie = new GoodMovieSpecification(); | ||
var composed = pg13Rating.And(goodMovie); | ||
|
||
bool isSatisfiedBy = composed.IsSatisfiedBy(movie); | ||
|
||
isSatisfiedBy.ShouldEqual(true); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
using System.Linq.Expressions; | ||
|
||
namespace SpecificationPattern { | ||
|
||
internal class ParameterReplacer : ExpressionVisitor { | ||
|
||
private readonly ParameterExpression _parameter; | ||
|
||
protected override Expression VisitParameter(ParameterExpression node) | ||
=> base.VisitParameter(_parameter); | ||
|
||
internal ParameterReplacer(ParameterExpression parameter) { | ||
_parameter = parameter; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,81 +1,76 @@ | ||
using System; | ||
using System.Linq; | ||
using System.Linq.Expressions; | ||
|
||
|
||
namespace SpecificationPattern | ||
{ | ||
public abstract class Specification<T> | ||
{ | ||
namespace SpecificationPattern { | ||
|
||
public abstract class Specification<T> { | ||
|
||
public abstract Expression<Func<T, bool>> ToExpression(); | ||
|
||
|
||
public bool IsSatisfiedBy(T entity) | ||
{ | ||
public bool IsSatisfiedBy(T entity) { | ||
Func<T, bool> predicate = ToExpression().Compile(); | ||
return predicate(entity); | ||
} | ||
|
||
|
||
public Specification<T> And(Specification<T> specification) | ||
{ | ||
public Specification<T> And(Specification<T> specification) { | ||
return new AndSpecification<T>(this, specification); | ||
} | ||
|
||
|
||
public Specification<T> Or(Specification<T> specification) | ||
{ | ||
public Specification<T> Or(Specification<T> specification) { | ||
return new OrSpecification<T>(this, specification); | ||
} | ||
} | ||
|
||
|
||
public class AndSpecification<T> : Specification<T> | ||
{ | ||
public class AndSpecification<T> : Specification<T> { | ||
private readonly Specification<T> _left; | ||
private readonly Specification<T> _right; | ||
|
||
|
||
public AndSpecification(Specification<T> left, Specification<T> right) | ||
{ | ||
public AndSpecification(Specification<T> left, Specification<T> right) { | ||
_right = right; | ||
_left = left; | ||
} | ||
|
||
|
||
public override Expression<Func<T, bool>> ToExpression() | ||
{ | ||
public override Expression<Func<T, bool>> ToExpression() { | ||
Expression<Func<T, bool>> leftExpression = _left.ToExpression(); | ||
Expression<Func<T, bool>> rightExpression = _right.ToExpression(); | ||
|
||
BinaryExpression andExpression = Expression.AndAlso(leftExpression.Body, rightExpression.Body); | ||
var paramExpr = Expression.Parameter(typeof(T)); | ||
var exprBody = Expression.AndAlso(leftExpression.Body, rightExpression.Body); | ||
exprBody = (BinaryExpression)new ParameterReplacer(paramExpr).Visit(exprBody); | ||
var finalExpr = Expression.Lambda<Func<T, bool>>(exprBody, paramExpr); | ||
|
||
return Expression.Lambda<Func<T, bool>>(andExpression, leftExpression.Parameters.Single()); | ||
return finalExpr; | ||
} | ||
} | ||
|
||
|
||
public class OrSpecification<T> : Specification<T> | ||
{ | ||
public class OrSpecification<T> : Specification<T> { | ||
private readonly Specification<T> _left; | ||
private readonly Specification<T> _right; | ||
|
||
|
||
public OrSpecification(Specification<T> left, 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(); | ||
|
||
BinaryExpression andExpression = Expression.OrElse(leftExpression.Body, rightExpression.Body); | ||
public override Expression<Func<T, bool>> ToExpression() { | ||
var leftExpression = _left.ToExpression(); | ||
var rightExpression = _right.ToExpression(); | ||
var paramExpr = Expression.Parameter(typeof(T)); | ||
var exprBody = Expression.OrElse(leftExpression.Body, rightExpression.Body); | ||
exprBody = (BinaryExpression)new ParameterReplacer(paramExpr).Visit(exprBody); | ||
var finalExpr = Expression.Lambda<Func<T, bool>>(exprBody, paramExpr); | ||
|
||
return Expression.Lambda<Func<T, bool>>(andExpression, leftExpression.Parameters.Single()); | ||
return finalExpr; | ||
} | ||
} | ||
} |