我如何使用C#lambda表达式语法调用另一个表达式?

时间:2011-09-04 10:09:52

标签: .net linq expression-trees

.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是表达式的事实。

1 个答案:

答案 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扩展名。