2014-03-09

理解 PredicateBuilder 實作方式

PredicateBuilder 提供了以 OR 串接 bool 的 Lambda Expression,使用上會像下面的程式:
var predicate = PredicateBuilder.False<Product>();

predicate = predicate.Or(p => p.Name == 'Shoe');
predicate = predicate.Or(p => p.Price > 100);


它的原始碼如下:
public static Expression<Func<T, bool>> Or<T> (
    this Expression<Func<T, bool>> expr1,
         Expression<Func<T, bool>> expr2
)
{
    var invokedExpr = Expression.Invoke (
        expr2, 
        expr1.Parameters.Cast<Expression>()
    );
 
    return Expression.Lambda<Func<T, bool>>(
        Expression.OrElse (expr1.Body, invokedExpr), 
        expr1.Parameters
    );
}


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


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

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

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

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


參考來源:
Dynamically Composing Expression Predicates

0 回應: