2013-11-08 4 views
17

Я понять PredicateBuilder методы расширения, написанные Джозеф Albahari, и я видел это Expression.Invoke и честно говоря, я не мог понять причину этого в следующем методе:Понимание 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); 
} 

Даже хотя он объяснил это немного:

Интересная работа проходит внутри методов «И» и «Или». Мы начинаем с вызова второго выражения с параметрами первого выражения . Выражение Invoke вызывает другое выражение лямбда, используя данные выражения в качестве аргументов. Мы можем создать условное выражение из тела первого выражения и вызванного варианта второго. Последний шаг - обернуть это в новое выражение лямбда .

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

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

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

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

Вопросы:

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

Update:

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

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

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

ответ

28

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

+1

Хотелось бы, чтобы я мог дать вам больше очков, но вы объяснили это очень хорошо! Спасибо! – Tarik

+2

А также ваши ответы очистили всю концепцию «Выражение» в моем сознании :) – Tarik

Смежные вопросы