WEB开发网
开发学院软件开发C语言 趣味编程:C#中Specification模式的实现(参考答案... 阅读

趣味编程:C#中Specification模式的实现(参考答案 - 下)

 2010-09-30 21:01:37 来源:WEB开发网   
核心提示: Expression<Func<int,bool>>f=i=>i%2==0;f=f.Not();foreach(variinnewint[]{1,2,3,4,5,6}.AsQueryable().Where(f)){Console.WriteLine(i);}打印出

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; 
  } 
} 

上一页  1 2 3 4  下一页

Tags:趣味 编程 Specification

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接