0

我正在使用来自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);

我不太明白解释。有人可以解释一下上面扩展方法的代码是如何工作的吗?谢谢

4

1 回答 1

0

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

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

我们还应该记住,expr1您现有的表达式采用 aT并返回 a bool。此外,虽然我们正在使用的表达式树实际上并没有任何事情(它们代表了一些东西),但我以后将使用“do”,因为它更容易阅读。从技术上讲,要使表达式树实际执行某些操作,您必须先对其进行编译,然后再调用生成的委托。

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

aBinaryExpression表示条件 OR 运算,仅当第一个操作数的计算结果为 false 时才计算第二个操作数。

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

于 2013-03-15T15:42:32.133 回答