Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/mongodb/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 表达式树和调用委托_C#_.net_Lambda_Delegates_Expression Trees - Fatal编程技术网

C# 表达式树和调用委托

C# 表达式树和调用委托,c#,.net,lambda,delegates,expression-trees,C#,.net,Lambda,Delegates,Expression Trees,因此,我有一个委托,它指向一些函数,当我第一次创建委托对象时,我实际上并不知道这些函数。该对象稍后被设置为某个函数 然后我还想创建一个表达式树,用一个参数调用委托(为了解决这个问题,参数可以是5)。这是我正在挣扎的一点;下面的代码显示了我想要的内容,但它没有编译 Func<int, int> func = null; Expression expr = Expression.Invoke(func, Expression.Constant(5)); 这似乎意味着要使用委托func,

因此,我有一个
委托
,它指向一些函数,当我第一次创建
委托
对象时,我实际上并不知道这些函数。该对象稍后被设置为某个函数

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

Func<int, int> func = null;
Expression expr = Expression.Invoke(func, Expression.Constant(5));
这似乎意味着要使用
委托
func
,我需要生成
值(Test.Program+c\u DisplayClass0).func

那么,如何创建调用委托的表达式树呢?

这应该可以:

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

// If func is null like in your example, the GetType() call fails, 
// so give it a body or use typeof if you know the type at compile time
var param = Expression.Parameter(func.GetType());

// Call the Invoke method on the delegate, which is the same as invoking() it
var callExpr = Expression.Call(param, func.GetType().GetMethod("Invoke"), Expression.Constant(5)); 

var lambdaExpr = Expression.Lambda<Action<Action<int>>>(callExpr, param); 

var fn = lambdaExpr.Compile(); // Compile the expression tree so it can be executed 

fn(func); // Prints 25

我唯一能想到的另一种方法是捕获闭包中本地声明的委托,但我不知道怎么做

我认为您要做的是使用要传递的委托的Target和Method属性来创建调用表达式。以朱利安的样本为基础,这就是它的样子:

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
Action func=i=>Console.WriteLine(i*i);
var callExpr=Expression.Call(Expression.Constant(func.Target)、func.Method、Expression.Constant(5));
var lambdaExpr=Expression.Lambda(调用方xpr);
var fn=lambdaExpr.Compile();
fn();//印刷品25
好的,这说明了如何做到这一点(但在我看来这是非常不雅观的):

Func Func=null;
表达式bind=(x)=>func(x);
Expression expr=Expression.Invoke(bind,Expression.Constant(5));
表达式lambda=表达式.lambda(expr);
Func compiled=lambda.Compile();
控制台写入线(expr);
func=x=>3*x;
Console.WriteLine(compiled());
func=x=>7*x;
Console.WriteLine(compiled());
Console.Read();

基本上我使用
(x)=>func(x)
生成一个调用委托指向的内容的函数。但是您可以看到,
expr
过于复杂。由于这个原因,我不认为这个答案是好的,但也许它可以建立在

< P>而其他答案提供了一些工作方式,有一个较短的方法:

Expression.Invoke(Expression.Constant(my\u delegate),参数\u表示\u delegate)


它既适用于引用静态方法的委托,也适用于引用实例方法的委托,不做任何更改。

这与我想要的非常接近,但我不想将委托作为参数传递。编辑假定我知道函数,但在创建表达式之前我不知道函数。函数本身并不一定是一个表达式。闭包的想法听起来很有希望。我必须用null替换Expression.Constant(func.Target)才能让它工作。但这绑定到函数func当前指向的内容,而不是它以后可能指向的内容。问题是不能对func指向什么做任何假设,它可能会随时更改。这几乎是我需要的答案,但请从Expression.Call中删除第一个参数。否则,就会出现一个异常(我同时检查了.NET4和.NET4.5)@讽刺的是:当您进行测试时,目标方法是静态方法吗?这可能就是区别。目标实际上是您示例中的一个:i=>Console.WriteLine(i*i),它是静态的,因为它不引用任何内容。您创建的表达式需要有一种通过引用访问func变量的方法。无法创建对局部变量的引用。在您的代码中,您使用bind lambda来捕获局部变量,而C#编译器发挥其魔力,创建一个单独的类来保存看起来像局部变量的内容。你可以自己做这件事,不必使用bind表达式,但是得到的lambda可能同样复杂。我想这需要一些来自反射的魔法。发射?在表达式树上有一个详细的部分。虽然这段代码可能会回答这个问题,但提供关于如何和/或为什么解决这个问题的附加上下文将提高答案的长期价值。@Nic3500我当然同意,但我觉得我不适合在上面展开讨论。我只是注意到有很多答案在某种程度上是有效的,但并不是普遍有效的。投票最多的答案不适用于引用静态方法iirc的代表。公认的答案显然太复杂了。我将答案改为“社区维基”,以便有人可以扩展它。
Action<int> func = i => Console.WriteLine(i * i);

// If func is null like in your example, the GetType() call fails, 
// so give it a body or use typeof if you know the type at compile time
var param = Expression.Parameter(func.GetType());

// Call the Invoke method on the delegate, which is the same as invoking() it
var callExpr = Expression.Call(param, func.GetType().GetMethod("Invoke"), Expression.Constant(5)); 

var lambdaExpr = Expression.Lambda<Action<Action<int>>>(callExpr, param); 

var fn = lambdaExpr.Compile(); // Compile the expression tree so it can be executed 

fn(func); // Prints 25
 var arg = Expression.Parameter(typeof(int), "i");

 var multiply = Expression.Multiply(arg, arg);

 var writeln = Expression.Call(typeof(Console).GetMethod("WriteLine", 
   new[] { typeof(int) }), multiply);

 var lambda = Expression.Lambda<Action<int>>(writeln, arg);

 var compiled = lambda.Compile();

 compiled(5); // Prints 25
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
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();