c#表达式中的闭包变量捕获问题

我有一个使用表达式树创建委托的函数。 在这个表达式中,我使用从传入函数的多个参数中捕获的变量。 实际的表达式树相当大,例如:

Delegate GenerateFunction(T current, IList parents) { var currentExpr = Expression.Parameter(typeof(T), "current"); var parentsExpr = Expression.Parameter(parents.getType(), "parents"); var parameters = new List(); .... return Expression.Lambda(Expression.Block(new List { parentsExpr, currentExpr }, ....), parameters.ToArray()).Compile(); } 

然后,我在将该函数传递给另一个要使用的函数之前,从另一个方法调用此方法。 完成所有操作后,我想访问在表达式树中更新的父项内容。

一切似乎都在编译,我的表达式看起来还不错,但是当我运行它时,我出现(虽然我不能确定)在访问parent变量时(在表达式/闭包内)获取空引用exception。

我想我想知道我做错了什么,或者这是否可行,以及了解发生了什么的提示。 我似乎无法在方法中找到任何悬挂的(?)局部变量,所以我想知道它们是否被捕获了?

谢谢,马克

我似乎无法在方法中找到任何悬挂的局部变量,所以我想知道它们是否被捕获了?

看起来您正在通过“手动”调用工厂方法来自己构建表达式树lambda。 编译器不知道你正在做什么; 它只是看到方法调用。 如果你想要提升当地人,那么你将不得不(1)让编译器为你做这件事, 让它重写lambda,或者(2)自己提升他们。

那是:

 int x = 123; Expression> ex = ()=>x; 

编译器重写lambda并为你提升它,就像你说的那样:

 Closure c = new Closure(); cx = 123; Expression> ex = ()=>cx; 

其中c通常变为常量表达式。

但如果你说

 Expression> ex = Expression.Lambda( ...something that uses x ... ); 

编译器不知道你正在做一些需要提升x的东西; x不在lambda表达式中。 如果您正在使用工厂,编译器会假设您知道自己在做什么,并且不会重写它。 你必须自己提升它。

我想你正在寻找Expression.Quote ,它支持Lambda表达式中的变量捕获。 基本上,内部LambdaExpression (将引用捕获的变量)需要包含在Expression.Quote(...)调用中。

这里的示例和讨论: Expression.Quote()做了什么,Expression.Constant()不能做什么?