我需要复杂的多种类型(<TLeft,TRight>
)规范赞:
public class AndSopecification<TLeft,TRight>
{
public AndSpecification(ISpecification<TLeft> leftSide, ISpecification<TRight> rightSide)
{
}
.
.
.
}
但我看到的所有规范示例都是实现单一类型(<T>
),如:
public sealed class AndSpecification<T> : CompositeSpecification<T>
{
public AndSpecification(ISpecification<T> leftSide, ISpecification<T> rightSide)
{
}
.
.
.
}
如果我创建如下的复杂规范,是否有任何问题:
new AndSpecification<Foo,Bar>(new FooSpecification(),new BarSpecification()).SatisfiedBy();
因此,我可以在不同情况下重复使用所有规范,然后我可以拥有单个唯一的过程点,这些过程点可以是更复杂的规范树的组合单元。
但我找不到那样的实现。
我是在正确的道路上吗?
修改
我正在将客户使用的每个条件句翻译成specification
并在客户重用句子的任何地方重复使用
(在每个相关的logic
,query predicate
,business rule validation
,...中,我认为这些specifications
在这些情况中自然是相同的)
正如客户所做的那样,我创建了composite specifications
,
但我在每种情况下都使用不同的基础架构访问它们(query predicate
,business rule validation
,...)
答案 0 :(得分:1)
我有一个实现,我可以执行以下操作,这使我能够重用我认为合适的规范。
public class Composite
{
public Foo _foo;
public Bar _bar;
}
var fooSpec = new Specification<Foo>(f => f.IsActive);
var barSpec = new Specification<Bar>(f => f.IsActive);
var comSpec = new Specification<TheComposite>(c => true);
comSpec = comSpec.And(c => c.Foo, fooSpec)
.And(c => c.Bar, barSpec);
如果这是您正在寻找的,我就是这样做的。
public class Specification<TEntity>
{
private readonly Expression<Func<TEntity, bool>> _expression;
public static Specification<TEntity> Create<TNestedEntity>(Expression<Func<TEntity, TNestedEntity>> propertyExpression, ISpecification<TNestedEntity> spec)
{
var replacer = new ParameterReplaceVisitor(spec.EvalExpression.Parameters.First(), propertyExpression.Body);
var newExpression = replacer.Visit(spec.EvalExpression.Body);
var exp = Expression.Lambda<Func<TEntity, bool>>(newExpression, propertyExpression.Parameters);
return new Specification<TEntity>(exp);
}
public virtual bool IsSatisfiedBy(TEntity e)
{
return EvalFunc(e);
}
public ISpecification<TEntity> And(ISpecification<TEntity> other)
{
return new Specification<TEntity>(EvalExpression.And(other.EvalExpression));
}
public ISpecification<TEntity> And<TNestedEntity>(Expression<Func<TEntity, TNestedEntity>> property, ISpecification<TNestedEntity> spec)
{
return And(Create(property, spec));
}
...
}
private class ParameterReplaceVisitor : ExpressionVisitor
{
private readonly Expression _replacementExpression;
private readonly ParameterExpression _parameter;
public ParameterReplaceVisitor(ParameterExpression parameter, Expression replacementExpression)
{
_parameter = parameter;
_replacementExpression = replacementExpression;
}
protected override Expression VisitParameter(ParameterExpression node)
{
// If the node is the parameter we are trying to replace,
// return the expression that should replace it.
return (node == _parameter) ? _replacementExpression : node;
}
}
ExpressionVisitor是System.Linq.Expressions
的一部分您当然也可以实现Or()
我希望这是你正在寻找的,这会有所帮助。
答案 1 :(得分:1)
创建与特定类型的对象无关的规范会破坏目的。来自Eric Evans:&#34; SPECIFICATION是一个谓词,用于确定某个对象是否满足某些条件。&#34;因此,您始终必须针对实例评估规范。复合规范用于组成与同一类对象相关的规范。
规范与业务规则不同。您可以使用多个规范的业务规则。例如:如果客户想购买一辆大型汽车,那么他需要在他的银行账户中存一些钱。
var bigCar = new Specification<Car>(car => car.Size == "big");
var accountHasMoney = new Specification<Account>(account => account.Balance > 0);
// This rule takes a car and an account
public bool CanBuyBigCar(Car car, Account account) {
return bigCar.IsSatisfiedBy(car) && accountHasMoney.IsSatisfiedBy(account)
}
如果要在sql查询中重用这些规范,那么可以使用隐式运算符使其更容易与IQueryables一起使用:
public static implicit operator Expression<Func<T, bool>>(Specification<T> specification)
{
return specification.Expression;
}
public static implicit operator Func<T, bool>(Specification<T> specification)
{
return specification.IsSatisfiedBy;
}
现在所有IQueryables,IEnumerables和所有其他类型的集合都可以直接查询规范。
您可以在此处找到即用型实施:https://github.com/jnicolau/NSpecifications/tree/master/Nspecifications
答案 2 :(得分:1)
我很难理解为什么需要指定多个类型。但是没有理由您不能这样做。从技术上讲,您可以使用一个元组规范。
var spec = new Spec<(int num, string text)>(x => x.num == 1 && x.text == "a");