Лямбда-выражения и как их объединить?
Как я могу объединить два лямбда-выражения в один, используя OR?
Я пробовал следующее, но для их слияния мне нужно передать параметры в вызовы Expression.Invoke, однако я хочу, чтобы значение, переданное в новую лямбду, передавалось на каждую дочернюю лямбда.
Expression<Func<int, bool>> func1 = (x) => x > 5;
Expression<Func<int, bool>> func2 = (x) => x < 0;
//Combines the lambdas but result in runtime error saying I need to pass in arguments
//However I want the argument passed into each child lambda to be whatever is passed into the new main lambda
Expression<Func<int, bool>> lambda = Expression.Lambda<Func<int, bool>>(Expression.Or(Expression.Invoke(func1), Expression.Invoke(func2)));
//The 9 should be passed into the new lambda and into both child lambdas
bool tst = lambda.Compile().Invoke(9);
Любые идеи о том, как объединить два лямбда-выражения в единицу и иметь аргументы дочернего lambdas как родительского?
Ответы
Ответ 1
Лучший способ найти выражения - это посмотреть исходный код PredicateBuilder.
Если вы хотите объединить несколько своих операторов, вы можете:
Expression<Func<int, bool>> func1 = (x) => x > 5;
Expression<Func<int, bool>> func2 = (x) => x > 10;
var invocation = Expression.Invoke(func2, func1.Parameters.Cast<Expression>());
var expression = Expression.Lambda<Func<int, bool>>(Expression.OrElse(func1.Body, invocation), func1.Parameters);
Expression.Invoke
создает InvocationExpression, которое применяет параметры к вашему func2
.
Фактически, PredicateBuilder может быть всем, что вам нужно.
var predicate = PredicateBuilder.False<int>();
predicate = predicate.Or(x => x > 5);
predicate = predicate.Or(x => x > 10);
Я бы пересмотрел "x > 5
или x > 10
", по-видимому, это странно для OR.
Надеюсь, что это поможет.
Ответ 2
Звук интересный... Я мало знаю о лямбда-выражении, но нашел эту статью. В исходном коде PredicateBuilder приведен пример или работает для меня:
public static Expression<Func<T, bool>> Or<T>(
this Expression<Func<T, bool>> expr1,
Expression<Func<T, bool>> expr2 )
{
var invExpr = Expression.Invoke( expr2, expr1.Parameters.Cast<Expression>() );
return Expression.Lambda<Func<T, bool>>
( Expression.OrElse( expr1.Body, invExpr ), expr1.Parameters );
}
Ответ 3
Почему бы просто не сделать:
Func<int, bool> func1 = (x) => x > 5;
Func<int, bool> func2 = (x) => x > 10;
List<Func<int, bool>> funcs = new List<Func<int, bool>> { func1, func2 };
var value = 7;
Console.WriteLine(funcs.Any(x => x(value))); // OR
Console.WriteLine(funcs.All(x => x(value))); // AND
?
Сохраняет беспорядок с сторонними библиотеками.
Ответ 4
** edit: oops читает предмет OR, обновляет его ***
Привет,
Не уверен, что вы просто хотите назвать их seperatley или хотите объединить их с академической точки зрения.
Вы можете просто называть их следующим образом:
bool OR(int i1, Func<int, bool> f1, Func<int, bool> f2){
return f1(i1) || f2(i1);
}
Это сделает трюк.
или вы можете переписать это как
bool MyOR = (i1, f1, f2) => f1(i1) || f2(i1);
И когда вы доброжелательны, создайте выражение из этого и посмотрите на это. (делаю это вручную, у нас нет VS здесь, поэтому, пожалуйста, будьте спокойны в моих опечатках)
Expression<Func<int, Func<int, bool>, Func<int, bool>, bool>> exprOR =
(i1, f1, f2) => f1(i1) || f2(i1);
Если вы хотите посмотреть на анатомию выражения, вы можете посмотреть на эту статью, которую я написал: http://www.codeproject.com/KB/WPF/WpfExpressionTree.aspx
Просто передайте выражение в apadater и посмотрите, как он создан.
С уважением Герт-Ян