趣味编程:C#中Specification模式的实现(参考答案 - 下)
2010-09-30 21:01:37 来源:WEB开发网Expression<Func<int, bool>> f = i => i % 2 == 0;
f = f.Not();
foreach (var i in new int[] { 1, 2, 3, 4, 5, 6 }.AsQueryable().Where(f))
{
Console.WriteLine(i);
}
打印出来的自然是所有的奇数,即1、3、5。
而And和Or的处理上会有所麻烦,我们不能这样像Not一样简单处理:
public static Expression<Func<T, bool>> And<T>(
this Expression<Func<T, bool>> one, Expression<Func<T, bool>> another)
{
var candidateExpr = one.Parameters[0];
var body = Expression.And(one.Body, another.Body);
return Expression.Lambda<Func<T, bool>>(body, candidateExpr);
}
这么做虽然能够编译通过,但是在执行时便会出错。原因在于one和another两个表达式虽然都是同样的形式(Expression<Func<T, bool>>),但是它们的“参数”不是同一个对象。也就是说,one.Body和another.Body并没有公用一个 ParameterExpression实例,于是我们无论采用哪个表达式的参数,在Expression.Lambda方法调用的时候,都会告诉您新的 body中的某个参数对象并没有出现在参数列表中。
于是,我们如果要实现And和Or,做的第一件事情便是统一两个表达式树的参数,于是我们准备一个ExpressionVisitor:
internal class ParameterReplacer : ExpressionVisitor
{
public ParameterReplacer(ParameterExpression paramExpr)
{
this.ParameterExpression = paramExpr;
}
public ParameterExpression ParameterExpression { get; private set; }
public Expression Replace(Expression expr)
{
return this.Visit(expr);
}
protected override Expression VisitParameter(ParameterExpression p)
{
return this.ParameterExpression;
}
}
Tags:趣味 编程 Specification
编辑录入:爽爽 [复制链接] [打 印]更多精彩
赞助商链接