了解Expression.Invoke()方法

时间:2013-11-08 23:25:01

标签: c# expression-trees

我一直在理解约瑟夫·阿尔巴哈里写的PredicateBuilder扩展方法,我看到了这个Expression.Invoke,说实话,我无法理解下面方法中的原因:

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

尽管他解释了一下:

  

有趣的工作发生在And和Or方法中。我们   首先使用第一个表达式调用第二个表达式   参数。 一个Invoke表达式使用调用另一个lambda表达式   给定的表达式作为参数。我们可以创建条件   表达式来自第一个表达式的主体和被调用的表达式   第二步的版本。最后一步是将它包装在一个新的lambda中   表达

MSDN告诉我:

  

创建一个应用委托或lambda的InvocationExpression   表达式到参数表达式列表。

这对我来说很有意义。所以基本上我不必传入任何参数,如果我使用这样的表达式。

但由于某种原因,我无法理解它。也许我累了或者别的什么。

问题:

  1. 何时以及在何种情况下使用InvocationExpression
  2. 是有意义的
  3. 任何人都可以解释Or<T>方法(或AndElse<T>)方法的效果如何?
  4. 更新

    当我下班回家时,我正在考虑InvocationExpression,这在我脑海中暗示着这样:

    当我们调用一个方法时,我们简单地说CallMe(phoneNumber, time);,这称为方法调用。然后,InvocationExpression应该是表达CallMe(phoneNumber, time);的表达式。它类似于LambdaExpression表示lambda,例如t => t + 2。所以基本上它是一个应用于参数(而不是参数)的方法调用。因此,作为调用,不再需要参数,但可能会返回一些内容,因为参数已经应用于其参数。

    有关我正在讨论的代码的详细信息,请访问http://www.albahari.com/nutshell/predicatebuilder.aspx

1 个答案:

答案 0 :(得分:37)

想象一下,你没有使用表达式,而是使用代表。然后你可以像这样写Or

public static Func<T, bool> Or<T>(this Func<T, bool> expr1, Func<T, bool> expr2)
{
    return x => expr1(x) || expr2(x);
}

您创建一个新委托,使用||调用两个委托。当您重写此表达式以使用表达式时,调用委托会变为Expression.Invoke()

public static Expression<Func<T, bool>> Or<T>(
    this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
{
    var parameter = Expression.Parameter(typeof(T), "x");
    var invokedExpr1 = Expression.Invoke(expr1, parameter);
    var invokedExpr2 = Expression.Invoke(expr2, parameter);

    return Expression.Lambda<Func<T, bool>>(
        Expression.OrElse(invokedExpr1, invokedExpr2), parameter);
}

实际Or不是这样编写的原因(很可能)是一种优化:您不必调用这两个表达式,您可以重用其中一个表达式的主体和参数。 (但是你不能重复使用它们,因为它们有不同的参数。)