简体   繁体   English

创建一个调用方法的表达式树

[英]Creating an expression tree that calls a method

Is it possible to create an expression tree that directly calls a method? 是否可以创建直接调用方法的表达式树? For example, consider the following method: 例如,请考虑以下方法:

public static int MyFunc(int a, int b)
{
    return a + b;
}

I would like to create an expression tree that calls MyFunc with parameters a=1 and b=2. 我想创建一个表达式树,调用MyFunc参数a = 1和b = 2。 One way to accomplish this is with reflection: 实现这一目标的一种方法是反思:

var c1 = Expression.Constant(1);
var c2 = Expression.Constant(2);
var expr = Expression.Call(typeof(Program).GetMethod("MyFunc"), c1, c2);

However, this is disadvantageous because reflection is slow and turns what should be compile-time errors into run-time errors. 但是,这是不利的,因为反射很慢并且应该将编译时错误转换为运行时错误。

I could use the following approach instead: 我可以使用以下方法:

Expression<Func<int, int, int>> lambda = (a, b) => MyFunc(a, b);
var expr = Expression.Invoke(lambda, c1, c2);

But this is still not what I want because it wraps the method in a lambda expression instead of calling it directly. 但这仍然不是我想要的,因为它将方法包装在lambda表达式中而不是直接调用它。

A good solution might be based on a delegate, like this: 一个好的解决方案可能基于委托,如下所示:

Func<int, int, int> del = Program.MyFunc;
var expr = Expression.Invoke(del, c1, c2);

Unfortunately, that does not compile because del is a delegate rather than an expression. 不幸的是,这不会编译,因为del是委托而不是表达式。 Is there any way to build an expression from a delegate? 有没有办法从委托构建表达式? (Note that I know the target of the delegate at compile-time, so I don't need the kind of flexibility described here: Expression Trees and Invoking a Delegate .) (注意,我在编译时知道委托的目标,所以我不需要这里描述的那种灵活性: 表达式树和调用委托 。)

A non-delegate solution would also be fine, as long as it calls the target method as directly as possible. 非委托解决方案也可以,只要它尽可能直接调用目标方法。

Update: This also works, but it still relies on reflection: 更新:这也有效,但它仍然依赖于反射:

Func<int, int, int> del = Program.MyFunc;
var expr = Expression.Call(del.Method, c1, c2);

At least it is more likely to catch problems at compile-time. 至少它更有可能在编译时捕获问题。 But it still pays the run-time price for reflection, doesn't it? 但它仍然支付反射的运行时价格,不是吗?

As long as you call .Compile on the lambda and store (and re-use) the delegate, you only pay the reflection price once. 只要你在lambda上调用.Compile并存储(并重新使用)委托,你只需支付反映价格一次。

var c1 = Expression.Constant(1);
var c2 = Expression.Constant(2);
var expr = Expression.Call(typeof(Program).GetMethod("MyFunc"), c1, c2);
Func<int> func = Expression.Lambda<Func<int>>(expr).Compile();
// ** now store func and re-use it **

However, to get a naked delegate to just that method, you can use: 但是,要使代理只使用该方法,您可以使用:

var method = typeof(Program).GetMethod("MyFunc");
Func<int, int, int> func = (Func<int, int, int>) Delegate.CreateDelegate(
         typeof(Func<int, int, int>), method);

of course, then you are forced to provide the constants at the caller. 当然,你被迫在调用者处提供常量。

Another option is DynamicMethod , but as long as you are caching the final delegate, this won't be significantly faster. 另一个选项是DynamicMethod ,但只要您缓存最终委托,这将不会明显加快。 It does offer more flexibility (at the price of complexity), but that doesn't seem to be the issue here. 它确实提供了更大的灵活性 (以复杂的代价),但这似乎不是问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM