开发者

How can I, using the C# lambda expression syntax, invoke another expression?

开发者 https://www.devze.com 2023-04-02 12:42 出处:网络
The .NET开发者_开发问答 Expression type has support for representing calling into a function defined by another expression, but is there a way of expressing this using the C# lambda expression syntax?

The .NET开发者_开发问答 Expression type has support for representing calling into a function defined by another expression, but is there a way of expressing this using the C# lambda expression syntax? I can generate one expression, compile it and call it in another expression but that loses the "expressionness" of the lambda being called, and the calling expression will only contain a reference to an anonymous compiled function.

I.e., what I want to do is something like:

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

but as it's not valid to call an Expression directly, the closest thing I have is:

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

... which loses the fact that the function f being called is an expression.


I don't believe this is currently possible to do with the compiler's help (as of C# 4.0), but you could of course do it "by hand" with Expression.Invoke.

Creates an InvocationExpression that applies a delegate or lambda expression to a list of argument expressions.

In your case, this would look something like:

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 provides the Invoke /Expand extension-methods that do the leg-work for you, giving you back the ability to use lambdas for this. This will let you do:

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();

..which is very close to the syntax you had originally wanted.

One point to note about InvocationExpressions is that some LINQ providers (such as LINQ to Entities) don't like them at all; so you'll have often have to 'expand' out the invoked expression so that it looks like one single expression to the provider. You can of course do this by hand, but LINQKit again comes in handy with the AsExpandable extension.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号