表达式树和调用委托

18 .net c# lambda delegates expression-trees

所以我有一个delegate指向我在第一次创建delegate对象时实际上并不知道的功能.稍后将该对象设置为某个功能.

然后我还想创建一个表达式树,用参数调用委托(为了这个问题,参数可以是5).这是我正在努力的一点点; 下面的代码显示了我想要的内容,但它没有编译.

Func<int, int> func = null;
Expression expr = Expression.Invoke(func, Expression.Constant(5));
Run Code Online (Sandbox Code Playgroud)

对于这个例子,我可以这样做(这是实用的,因为我需要在运行时构建表达式树):

Func<int, int> func = null;
Expression<Func<int>> expr = () => func(5);
Run Code Online (Sandbox Code Playgroud)

这使得expr成为:

() => Invoke(value(Test.Program+<>c__DisplayClass0).func, 5)
Run Code Online (Sandbox Code Playgroud)

这似乎意味着要使用delegate func,我需要产生value(Test.Program+<>c__DisplayClass0).func一点.

那么,我怎样才能创建一个调用委托的表达式树?

Dan*_*ted 14

我想你想要做的是使用委托的Target和Method属性来传递以创建一个Call表达式.基于JulianR的样本,这就是它的样子:

Action<int> func = i => Console.WriteLine(i * i);

var callExpr = Expression.Call(Expression.Constant(func.Target), func.Method, Expression.Constant(5));

var lambdaExpr = Expression.Lambda<Action>(callExpr);
var fn = lambdaExpr.Compile();
fn();    //  Prints 25
Run Code Online (Sandbox Code Playgroud)


小智 10

OK,这说明它是如何能够做到(但它是非常不雅的在我看来):

Func<int, int> func = null;
Expression<Func<int, int>> bind = (x) => func(x);

Expression expr = Expression.Invoke(bind, Expression.Constant(5));

Expression<Func<int>> lambda = Expression.Lambda<Func<int>>(expr);
Func<int> compiled = lambda.Compile();

Console.WriteLine(expr);

func = x => 3 * x;
Console.WriteLine(compiled());

func = x => 7 * x;
Console.WriteLine(compiled());

Console.Read();
Run Code Online (Sandbox Code Playgroud)

基本上我(x) => func(x);用来创建一个调用委托指向的函数.但你可以看到这expr太复杂了.出于这个原因,我不认为这个答案很好,但也许可以建立在它的基础之上?

  • 您创建的表达式需要有一种通过引用访问func变量的方法.您无法创建对局部变量的引用.在你的代码中,你使用bind lambda捕获局部变量,C#编译器运行它的魔法并创建一个单独的类来保存看起来像局部变量的东西.你可以自己做这个,你不必使用绑定表达式,但结果lambda可能会同样复杂. (2认同)
  • 我有兴趣看到"自己动手做法".我想它需要一些来自Reflection.Emit的魔法? (2认同)