2011-09-04 125 views
2

.NET表达式类型支持将调用表示为由另一个表达式定义的函数,但是有没有使用C#lambda表达式语法表达的方法?我可以生成一个表达式,编译它并在另一个表达式中调用它,但是失去了被调用lambda表达式的“表达式”,并且调用表达式将只包含对匿名编译函数的引用。如何使用C#lambda表达式语法调用另一个表达式?

也就是说,我想要做的是一样的东西:

Expression<Func<int, int>> f = x => x + x; 
Expression<Func<int, int>> g = x => 2 + f(x); 

,但因为它不是有效的直接调用的表达,我最接近的是:

Expression<Func<int, int>> f = x => x + x; 
var f_ = f.Compile(); 
Expression<Func<int, int>> g = x => 2 + f_(x); 

...这就失去了被调用函数f是一个表达式的事实。

回答

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 s的一点需要注意的是,一些LINQ提供者(如LINQ to Entities)根本不喜欢它们;所以你经常需要'扩展'被调用的表达式,以便它看起来像提供者的单个表达式。您当然可以手动完成此操作,但LINQKit可以再次与AsExpandable扩展一起使用。

+0

是的,我发现Expression.Invoke和InvocationExpression,这是我知道它可以代表。我很惊讶,没有办法用lambda表达式语法来表达它。实际上,使用lambda语法无法创建的所有表达式类型究竟是什么,大多数LINQ提供者是否支持它们? – SoftMemes

+0

优秀的答案,谢谢! – SoftMemes