【问题标题】:Lambda expressions and how to combine them?Lambda 表达式以及如何组合它们?
【发布时间】:2011-03-18 07:33:15
【问题描述】:

如何使用 OR 将两个 lambda 表达式合并为一个?

我尝试了以下方法,但合并它们需要我将参数传递到 Expression.Invoke 调用中,但是我希望将传递给新 lambda 的值传递给每个 child-lambda..

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

任何想法如何将两个 lambda 表达式组合为一个并让子 lambda 的参数成为父 lambda 的参数?

【问题讨论】:

  • 当你说“结合”时,你真正想要发生的事情是什么?假设传递的参数是 7 - func1 将返回 true,func2 将返回 false。您希望组合返回什么?

标签: c# .net linq generics lambda


【解决方案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 &gt; 5x &gt; 10”,这对 OR 来说似乎很奇怪。

希望对您有所帮助。

【讨论】:

  • 太好了,这正是我想要的。
  • 'Expression.Lamda' 缺少一个 'b',所以应该是 .Expression.Lambda'
  • 顺便说一句,Linq to Entities 不支持 Expression.Invoke。因此,尽管这将编译为 IL。它不会编译成 SQL。
【解决方案2】:

听起来很有趣……我对 lambda 表达式了解不多,但我找到了this article。在 PredicateBuilder Source Code 下是一个适合我的 or 示例:

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
    

    ?

    省去了使用 3rd 方库的麻烦。

    【讨论】:

    • 问题是我想把它们保存在一个表达式树中,所以它们被实体框架解析...
    • 很公平,我的建议可能不太可行
    【解决方案4】:

    ** 编辑:哎呀,读完了 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 并查看它是如何构建的。

    问候格特-扬

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多