Подтвердить что ты не робот

Понимание метода Expression.Invoke()

Я понимал методы расширения 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 вызывает другое лямбда-выражение, используя указанные выражения в качестве аргументов. Мы можем создать условное выражение из тела первого выражения и вызываемой версии второго. Последний шаг - обернуть это в новом лямбда-выражении.

MSDN говорит мне, что:

Создает InvocationExpression, которое применяет выражение делегата или лямбда к списку выражений аргументов.

и это имеет смысл для меня немного. Поэтому в основном мне не нужно передавать какие-либо аргументы, если я использую такое выражение.

Но почему-то я не мог этого понять. Может быть, я устал или что-то еще.

Вопросов:

  1. Когда и в какой ситуации имеет смысл использовать InvocationExpression.
  2. Может ли кто-нибудь объяснить, как метод Or<T> (или AndElse<T>) работает немного лучше?

Обновить:

Я думал об InvocationExpression когда я возвращался с работы на родину, и это намекало мне так:

Когда мы вызываем метод, мы просто говорим CallMe(phoneNumber, time); и это называется вызовом метода. Затем InvocationExpression должно быть выражением, которое выражает CallMe(phoneNumber, time); , Это похоже на выражение LambdaExpression которое выражает лямбда, например t => t + 2. Таким образом, в основном это вызов метода, который применяется к аргументам (а не параметрам). Таким образом, как вызов, он больше не нуждается в параметрах, но, возможно, возвращает что-то, поскольку аргументы уже применяются к его параметрам.

Для получения дополнительной информации о коде, о котором я говорю, посетите http://www.albahari.com/nutshell/predicatebuilder.aspx

4b9b3361

Ответ 1

Представьте, что вы не работали с выражениями, а с делегатами. Тогда вы могли бы написать 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 не написан подобным образом, является (скорее всего) оптимизацией: вам не нужно вызывать оба выражения, вы можете повторно использовать тело и параметр из одного из них. (Но вы не можете повторно использовать их оба, потому что у них разные параметры.)