Лямбда-выражения и как их объединить?

Как я могу объединить два лямбда-выражения в один, используя 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 и посмотрите, как он создан.

С уважением Герт-Ян