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

3

.NET表达式类型支持表示调用由另一个表达式定义的函数,但是否有一种使用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个回答

3
我不认为目前(C# 4.0)可以通过编译器实现这一点,但你当然可以手动使用Expression.Invoke来完成。

创建一个 InvocationExpression,将委托或 lambda 表达式应用于参数表达式列表。

在你的情况下,它看起来会是这样的:

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扩展方法,为您完成了繁琐的工作,使您能够再次使用lambda表达式。这将让您做到:

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扩展程序再次派上用场。


是的,我已经找到了Expression.Invoke和InvocationExpression,这就是我知道它可以表示的方式。我只是惊讶的是,没有办法使用lambda表达式语法来表示这一点。实际上,使用所有这些Expression类型的是什么,你不能使用lambda语法创建它们,大多数LINQ提供程序是否支持它们? - SoftMemes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接