Lambda 表达式以及如何组合它们?

Posted

技术标签:

【中文标题】Lambda 表达式以及如何组合它们?【英文标题】:Lambda expressions and how to combine them? 【发布时间】: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。您希望组合返回什么? 【参考方案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 并查看它是如何构建的。

问候格特-扬

【讨论】:

以上是关于Lambda 表达式以及如何组合它们?的主要内容,如果未能解决你的问题,请参考以下文章

在 C# 中组合两个 lambda 表达式

如何在不使用 Invoke 方法的情况下组合两个 lambda 表达式?

Kotlin的Lambda表达式以及它们怎样简化Android开发(KAD 07)

《Java8实战》 - 读书笔记 - Lambda 表达式的组合用法

Lambda表达式

使用 Lambda 表达式调用通用方法(以及仅在运行时知道的类型)