c# - 创建调用方法的表达式树

标签 c# reflection delegates lambda expression-trees

是否可以创建直接调用方法的表达式树?例如,考虑以下方法:

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

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

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, c1, c2);

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

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

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

不幸的是,这不会编译,因为 del 是一个委托(delegate)而不是一个表达式。有什么方法可以从委托(delegate)中构建表达式吗? (请注意,我在编译时知道委托(delegate)的目标,因此我不需要此处描述的那种灵 active :Expression Trees and Invoking a Delegate。)

非委托(delegate)解决方案也可以,只要它尽可能直接调用目标方法即可。

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

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

至少它更有可能在编译时发现问题。但它仍然要为反射付出运行时的代价,不是吗?

最佳答案

只要您在 lambda 上调用 .Compile 并存储(并重新使用)委托(delegate),您只需支付一次反射价格。

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 **

但是,要让委托(delegate)该方法,您可以使用:

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

当然,那么你必须在调用者处提供常量。

另一个选项是 DynamicMethod,但只要您缓存最终委托(delegate),它就不会显着更快。它确实提供了更多灵 active (以复杂性为代价),但这似乎不是这里的问题。

关于c# - 创建调用方法的表达式树,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3332268/

相关文章:

c# - IDateErrorInfo Multi Validation.ErrorTemplate

c# - 如何检查我是否可以对给定类型的值求和

java - 判断一个列表是否是另一个具有正确顺序的列表的有序子集的函数 c# 或 java

objective-c - .delegate=self 是什么意思?

c# - 由 MS Excel 和 COM 托管的 C#2 中的委托(delegate)中的异常行为

c# - 查询 Entity Framework 以获取动态类型列表

java - 理解 [[某些 Java 源代码中引用的 I.class

reflection - 在 PHPUnit 中使用反射

ios - 当我在 Swift 中将对象的委托(delegate)设置为 "self"时,编译器在做什么?

ios - 如何从 TextField 获取实时更改