有人可以进一步解释这个C#代码

时间:2013-03-15 15:14:17

标签: c#-4.0 lambda predicatebuilder

我正在使用http://www.albahari.com/nutshell/predicatebuilder.aspx

中的PredicateBuilder类
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);
  }

此扩展方法使用OR运算符链接谓词。在页面上,解释说

我们首先使用第一个表达式的参数调用第二个表达式。 Invoke表达式使用给定表达式作为参数调用另一个lambda表达式。我们可以从第一个表达式的主体和第二个表达式的调用版本创建条件表达式。最后一步是将它包装在一个新的lambda表达式中。


所以如果我有

Predicate<Book> p1 = b => b.Title.Contains("economy");
Predicate<Book> p2 = b=>b.PublicationYear>2001;
Predicate chain = p1.And(p2);

我没有完全得到这个问题。谁可以请解释上面的扩展方法的代码是如何工作的? 感谢

1 个答案:

答案 0 :(得分:0)

让我们像这样重写方法体:

return Expression.Lambda<Func<T, bool>>(
    Expression.OrElse(
        expr1.Body,
        Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>())
    ),
    expr1.Parameters);

我们还应该记住,expr1是您现有的表达式,它带有T并返回bool。另外,虽然我们正在使用的表达式树实际上并没有任何东西(它们代表某些东西),我今后将使用“do”因为它会带来很多更容易阅读。从技术上讲,表达式树实际上需要先执行compile,然后再调用生成的委托。

好的,我们这里有什么?这是一个lambda表达式,它接受expr1所采用的任何参数(参见最后一行),其主体(根据documentation)是

  

表示条件OR运算的BinaryExpression   仅当第一个操作数求值时才计算第二个操作数   假的。

第一个操作数是expr1.Body,这意味着结果函数(实际上不是函数,参见上面的注释)评估expr1。如果结果为true,则会在现场返回true。否则,它会调用expr2,其参数与传递给expr1的参数相同(这意味着单个T参数)并返回结果。