我有一个使用表达式树创建一个委托的函数.在这个表达式中,我使用从传入函数的多个参数捕获的变量.实际的表达式树是相当大的例子:
Delegate GenerateFunction<T>(T current,IList<T> parents) { var currentExpr = Expression.Parameter(typeof(T),"current"); var parentsExpr = Expression.Parameter(parents.getType(),"parents"); var parameters = new List<ParameterExpression>(); .... return Expression.Lambda(Expression.Block(new List<ParameterExpression> { parentsExpr,currentExpr },....),parameters.ToArray()).Compile(); }
然后在将该函数传递给另一个使用的函数之前,从另一种方法中调用此方法.一旦完成,我想访问在表达式树中更新的父母的内容.
一切似乎编译,我的表达式看起来很好,但是当我运行它时,我出现(虽然我不能确定)在访问父变量(表达式/闭包)内时得到空引用异常.
我想我想知道我是否做错了事情,或者这是否可能以及了解发生了什么的提示.我似乎无法在方法中找到任何提升的(?)局部变量,所以我想知道它们是否被捕获?
谢谢,
标记
解决方法
I don’t seem to be able to find any hoisted local variables within the method so I’m wondering whether they’re being captured at all?
看起来你正在自己构建表达式树lambda,通过“手动”调用工厂方法.编译器不知道这是你在做什么;它只是看到方法调用.如果你想要当地人被提升,那么你将不得不(1)让编译器为你做,通过重写lambda,或者(2)提升你自己.
那是:
int x = 123; Expression<Func<int>> ex = ()=>x;
编译器会重写lambda并将其提升给您,就像您所说的那样:
Closure c = new Closure(); c.x = 123; Expression<Func<int>> ex = ()=>c.x;
其中c通常变为Constant表达式.
但如果你说
Expression<Func<int>> ex = Expression.Lambda( ...something that uses x ... );
编译器不知道你在做什么,需要提升x; x不在lambda表达式内.如果您正在使用工厂,编译器会假设您知道您正在做什么,并且不会改变它.你必须自己提升.