在另一个lambda表达式中使用lambda表达式

我需要组合两个lambda表达式,第二个表达式“包含”第一个表达式。 我搜索了很多,但没有找到任何明确的答案……

我要做的是以下内容:第一个表达式“expression1”作为参数传递给方法,并且仅用于定义第二个lambda必须在哪个字段或属性上运行。

原理上,我正在尝试执行以下操作:

// simple field selector : Expression<Func> expression1 = obj => obj.field; // trying to use the field selector in 2nd expression : Expression<Func> e2 = obj => [[Result of expression1]].Equals("myValue"); 

换句话说,我想得到:

 Expression<Func> e2 = obj => obj.field.Equals("myValue"); 

我需要这样做,因为它并不总是被调用的Equals()方法,而是许多不同的方法。

我试图将expression1编译为Func以便在expression2中调用此Func,但是当我在LinQ中使用它时,我得到一个exception,因为LinQ不支持Invoke节点类型。

所以我的问题是:有没有办法将两个表达式的主体结合起来,请问有多喜欢?

谢谢提前!

好吧,这应该是诀窍:

 void Main() { var execute = Create( first => first.MyStringField, // field selector second => second.Equals("1234") // method selector ); Console.WriteLine(execute(new TestClass("1234"))); // true Console.WriteLine(execute(new TestClass("4321"))); // false } class TestClass { public string MyStringField; public TestClass(string val){ MyStringField = val; } } static Func Create( Expression> fieldSelector, Expression> methodSelector ) { // todo: classical validation of fieldSelector, if necessary. // todo: classical validation of methodSelector, if necessary. var compiledFieldSelector = fieldSelector.Compile(); var compiledMethodSelector = methodSelector.Compile(); return T => compiledMethodSelector(compiledFieldSelector(T)); } 

注意,由于lambda表达式的性质,您需要validation字段选择器和方法选择器,否则可能会做一些非常奇怪的事情。

或者,下一种方法创建不会“组合”事物的lambda,从某种意义上说,这更好,因为LinqToEntities不应该在解释查询时遇到问题。

  static Func Create( Expression> memberSelector, Expression> methodSelector ) { // todo: classical validation of memberSelector, if necessary. // todo: classical validation of methodSelector, if necessary. var memberExpression = (MemberExpression)(memberSelector.Body); var methodCallExpression = (MethodCallExpression)(methodSelector.Body); // input TSource => .. var input = Expression.Parameter(typeof(TSource)); var call = Expression.Call( Expression.MakeMemberAccess( input, memberExpression.Member), methodCallExpression.Method, methodCallExpression.Arguments); return Expression.Lambda>(call, input) .Compile(); } 

Chris Eelmaa的第二个答案是肯定的,只需删除.Compile()调用以避免出现Invokeexception:

 static Expression> Create( Expression> memberSelector, Expression> methodSelector ) { // todo: classical validation of memberSelector, if necessary. // todo: classical validation of methodSelector, if necessary. var memberExpression = (MemberExpression)(memberSelector.Body); var methodCallExpression = (MethodCallExpression)(methodSelector.Body); // input TSource => .. var input = Expression.Parameter(typeof(TSource)); var call = Expression.Call( Expression.MakeMemberAccess( input, memberExpression.Member), methodCallExpression.Method, methodCallExpression.Arguments); return Expression.Lambda>(call, input); } 

在我的情况下,然后像这样使用:( selector是一个像u => u.id的表达式, request是一个IQueryable ,都作为参数接收)

 Expression> contains = Create(selector, u => u.Contains(searchExpression)); IQueryable result = request.Where(contains);