2014-03-09 17:47

理解 PredicateBuilder 實作方式

PredicateBuilder 提供了以 OR 串接 bool 的 Lambda Expression,使用上會像下面的程式:
  1. var predicate = PredicateBuilder.False<Product>(); 
  2.  
  3. predicate = predicate.Or(p => p.Name == 'Shoe'); 
  4. predicate = predicate.Or(p => p.Price > 100); 


它的原始碼如下:
  1. public static Expression<Func<T, bool>> Or<T> ( 
  2.    this Expression<Func<T, bool>> expr1, 
  3.         Expression<Func<T, bool>> expr2 
  4. ) 
  5. { 
  6.    var invokedExpr = Expression.Invoke ( 
  7.        expr2,  
  8.        expr1.Parameters.Cast<Expression>() 
  9.    ); 
  10.  
  11.    return Expression.Lambda<Func<T, bool>>( 
  12.        Expression.OrElse (expr1.Body, invokedExpr),  
  13.        expr1.Parameters 
  14.    ); 
  15. } 


上面的程式雖然不長,但實在有點小難懂,搞不懂他為什麼要這麼寫??讓我們逐步解釋吧!


假設 expr1 是 x => x.Name == 'Shoe'
假設 expr2 是 y => y.Price > 100

  1. var invokedExpr = Expression.Invoke( 
  2.    expr2,  
  3.    expr1.Parameters.Cast<Expression>() 
  4. ); 
先組合出( 利用 expr1 的參數去執行 expr2 )的表示式 invokedExpr
產生出了語法會像 (y => y.Price > 100) (x)

  1. Expression.OrElse(expr1.Body, invokedExpr) 
將 expr1.Body 與 invokedExpr 以 || 運算子組合起來
產生出了語法會像 x.Name == 'Shoe' || (y => y.Price > 100) (x)

  1. Expression.Lambda<Func<T, bool>>( 
  2.    Expression.OrElse(expr1.Body, invokedExpr),  
  3.    expr1.Parameters 
  4. ); 
將剛剛組合好的 || 運算表示式再組合成 Lambda 表示式
產生出了語法會像 x => (x.Name == 'Shoe' || (y => y.Price > 100) (x))


參考來源:
Dynamically Composing Expression Predicates

0 回應: