组合Lambda表达式我正在寻找一种方法来组合两个lambda表达式,而无需在其中任何一个上使用Expression.Invoke。我想基本上构建一个链接两个单独表达式的新表达式。考虑以下代码:classModel{publicSubModelSubModel{get;设置;}}类SubModel{publicFooFoo{get;放;}}classFoo{publicBarBar{get;放;}}classBar{publicstringValue{get;放;我可以说我有两个表达式:Expressionexpression1=m=>m.SubModel.Foo;Expressionexpression2=f=>f.Bar.Value;我想设置Theseareconcatenated以获得函数的以下表达式:ExpressionjoinedExpression=m=>m.SubModel.Foo.Bar.Value;我能想到的唯一方法是像这样使用ExpressionVisitor:publicclassExpressionExtender:ExpressionVisitor{privatereadonlyExpression_baseExpression;publicExpressionExtender(ExpressionbaseExpression){_baseExpression=baseExpression;}protectedoverrideExpressionVisitMember(MemberExpressionnode){_memberNodes.Push(node.Member.Name);返回base.VisitMember(node);私人堆栈_memberNodes;publicExpressionExtend(Expressionextend){_memberNodes=newStack();base.Visit(扩展);varpropertyExpression=_memberNodes.Aggregate(_baseExpression.Body,Expression.Property);返回Expression.Lambda(propertyExpression,_baseExpression.Parameters);然后像这样使用它:varexpExt=newExpressionExtender(expression1);varjoinedExpression=expExt.Extend(expression2);它有效,但对我来说感觉有点笨拙我仍在努力思考表达式并想知道是否有更惯用的表达方式,我偷偷怀疑我遗漏了一些明显的东西。我想这样做的原因是为了将它与ASP.netmvc3Html助手一起使用。我有一些深度嵌套的ViewModel和一些HtmlHelper扩展来帮助解决这些问题,因此表达式只需要内置MVC帮助程序的MemberExpressions集合来正确处理它们并构建正确的深度嵌套名称属性值。我的第一直觉是使用Expression.Invoke()并调用第一个表达式并将其链接到第二个,但MVC助手不太喜欢它。它失去了等级背景。使用访问者将参数f的所有实例交换为m.SubModel.Foo并创建一个以m作为参数的新表达式:internalstaticclassProgram{staticvoidMain(){Expression>expression1=m=>m.SubModel.Foo;表达式>表达式2=f=>f.Bar.Value;varswap=newSwapVisitor(expression2.Parameters[0],expression1.Body);varlambda=Expression.Lambda>(swap.Visit(expression2.Body),expression1.Parameters);//测试它是否有效varfunc=lambda.Compile();模型测试=新模型{SubModel=newSubModel{Foo=newFoo{Bar=newBar{Value="abc"}}}};控制台.WriteLine(函数(测试));//"abc"}}classSwapVisitor:ExpressionVisitor{privatereadonlyExpressionfrom,to;publicSwapVisitor(Expressionfrom,Expressionto){this.from=from;这个.to=to;}publicoverrideExpressionVisit(Expressionnode){returnnode==from?到:base.Visit(节点);您的解决方案似乎只针对您的特定问题进行了狭隘的调整,这似乎是不灵活的。在我看来,您可以通过简单的lambda替换直接解决您的问题:用body替换参数的实例(或在lambda演算中称为“自由变量”)。(有关一些代码,请参阅Marc的回答。)由于表达式树中的参数具有引用标识而不是值标识,因此它们甚至不需要进行alpha重命名。也就是说,您有:表达式ab=a=>f(a);//可以是*any*expressionusingaExpression>bc=b=>g(b);//可以是*any*expressionusingb你想生成这个组件Expressionac=a=>g(f(a));//用f(a)替换所有b。因此,获取主体g(b)并进行搜索并替换调用者以查找b的ParameterExpression,并将其替换为主体f(a)为您提供新的主体g(f(a))。然后创建一个具有该主体的参数a的新lambda。更新:下面的答案会生成EF不支持的“调用”。我知道这是一个旧线程,但我有同样的需求,我想出了一个更简洁的方法来做到这一点。假设你可以把“expression2”改成user-generatedlambda,你可以这样注入:以上是C#学习教程:结合Lambda表达式所有分享的内容,如果对大家有用还需要了解更多关于C#学习教程,希望大家多多关注—classProgram{privatestaticExpression>GetValueFromFoo(FuncgetFoo){returnt=>getFoo(t).Bar.Value;}staticvoidMain(){表达式>getValueFromBar=GetValueFromFoo(m=>m.SubModel.Foo);//测试它是否有效varfunc=getValueFromBar.Compile();模型测试=新模型{SubModel=newSubModel{Foo=newFoo{Bar=newBar{Value="abc"}}}};安慰。写行(函数(测试));//"abc"}}本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处: