.NET Expression类型支持将调用表示为由另一个表达式定义的函数,但有没有办法使用C#lambda表达式语法来表达它?我可以生成一个表达式,编译它并在另一个表达式中调用它,但是它会丢失被调用的lambda的“表达式”,并且调用表达式将只包含对匿名编译函数的引用。
即,我想要做的是:
Expression<Func<int, int>> f = x => x + x;
Expression<Func<int, int>> g = x => 2 + f(x);
但由于直接调用Expression无效,我最接近的是:
Expression<Func<int, int>> f = x => x + x;
var f_ = f.Compile();
Expression<Func<int, int>> g = x => 2 + f_(x);
...失去了被调用的函数f是表达式的事实。
答案 0 :(得分:3)
我不相信目前可以使用编译器的帮助(从C#4.0开始),但您当然可以“手动”使用Expression.Invoke进行操作。
创建一个应用委托或lambda的InvocationExpression 表达式到参数表达式列表。
在您的情况下,这看起来像:
Expression<Func<int, int>> f = x => x + x;
var parameter = Expression.Parameter(typeof(int),"y");
var body = Expression.Add(Expression.Constant(2), Expression.Invoke(f, parameter));
// Loosely speaking: y => 2 + f(y)
var g = Expression.Lambda<Func<int, int>>(body, parameter);
LINQKit提供Invoke
/ Expand
扩展程序方法,为您提供腿部工作,让您重新使用lambdas。这将让你做到:
Expression<Func<int, int>> f = x => x + x;
Expression<Func<int, int>> g = x => 2 + f.Invoke(x);
// Note: 'Inlines' the invocation into the target expression.
var finalExpression = g.Expand();
.. 非常接近你原先想要的语法。
关于InvocationExpression
的一点要注意的是,一些LINQ提供程序(例如LINQ to Entities)根本不喜欢它们;因此,您经常需要“扩展”调用的表达式,使其看起来像是提供者的单个表达式。您当然可以手动执行此操作,但LINQKit再次派上用AsExpandable
扩展名。