加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

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

发布时间:2020-12-15 08:00:21 所属栏目:百科 来源:网络整理
导读:是否可以创建直接调用方法的表达式树?例如,请考虑以下方法: public static int MyFunc(int a,int b){ return a + b;} 我想创建一个表达式树,调用MyFunc参数a = 1和b = 2.实现这一目标的一种方法是反思: var c1 = Expression.Constant(1);var c2 = Express
是否可以创建直接调用方法的表达式树?例如,请考虑以下方法:
public static int MyFunc(int a,int b)
{
    return a + b;
}

我想创建一个表达式树,调用MyFunc参数a = 1和b = 2.实现这一目标的一种方法是反思:

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

但是,这是不利的,因为反射很慢并且应该将编译时错误转换为运行时错误.

我可以使用以下方法:

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

但这仍然不是我想要的,因为它将方法包装在lambda表达式中而不是直接调用它.

一个好的解决方案可能基于委托,如下所示:

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

不幸的是,这不会编译,因为del是委托而不是表达式.有没有办法从委托构建表达式? (注意,我在编译时知道委托的目标,所以我不需要这里描述的那种灵活性:Expression Trees and Invoking a Delegate.)

非委托解决方案也可以,只要它尽可能直接调用目标方法.

更新:这也有效,但它仍然依赖于反射:

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

至少它更有可能在编译时捕获问题.但它仍然支付反射的运行时价格,不是吗?

解决方法

只要您在lambda上调用.Compile并存储(并重新使用)委托,您只需支付反映价格一次.
var c1 = Expression.Constant(1);
var c2 = Expression.Constant(2);
var expr = Expression.Call(typeof(Program).GetMethod("MyFunc"),c2);
Func<int> func = Expression.Lambda<Func<int>>(expr).Compile();
// ** now store func and re-use it **

但是,要使裸代理只使用该方法,您可以使用:

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

当然,你被迫在调用者处提供常量.

另一个选项是DynamicMethod,但只要您缓存最终委托,这将不会明显加快.它确实提供了更大的灵活性(以复杂的代价),但这似乎不是问题.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读