问题在C#中的表达闭包变量捕获 [英] Issue with closure variable capture in c# expression

查看:83
本文介绍了问题在C#中的表达闭包变量捕获的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个创建一个使用表达式树的委托功能。在此表达我用从传递给函数的多个参数捕获的变量。实际表达式树是相当大,因此作为一个例子:

 代表GenerateFunction< T>(T电流,IList的< T>父母){
VAR currentExpr = Expression.Parameter(typeof运算(T),电流);
VAR parentsExpr = Expression.Parameter(parents.getType(),父母);
VAR参数=新的List< ParameterExpression>();

....

返回Expression.Lambda(Expression.Block(新名单< ParameterExpression> {parentsExpr,currentExpr},....),parameters.ToArray( ))编译()。
}



然后我传递给函数到另一个函数之前调用从另一个方法这个方法使用。一旦这一切都做我想要访问的父母它获取表达式树内更新的内容。



一切似乎编译和我的表情看起来不错,但是当我运行它似乎我(虽然我真的不能肯定)是访问变量父母(表达式/闭包)时,得到空引用异常。



我想我想知道如果我做错了或这是否可行,以及了解发生了什么事情的提示。我似乎并没有能够找到方法中,所以我想知道是否他们在所有被抓获的悬挂(?)局部变量?



谢谢,
选中


解决方案

我似乎没有能够找到任何悬挂在方法中的局部变量,所以我想知道是否他们都被抓获?




看起来你正在构建的表达树拉姆达自己,通过手动调用工厂方法。编译器不知道这是你在做什么;它只是看到的方法调用。如果你想当地人将被吊起,那么你就不得不要么(1)让编译器为你做,通过的的改写拉姆达,或(2)你自己扯起'时间



这就是:

  INT X = 123; 
表达式来; Func键< INT>>恩=()= X的催化剂;



编译器重写Lambda和升降机为你,好像你会说:

 关闭C =新的闭包(); 
c.x = 123;
表达式来; Func键< INT>> EX =()=> c.x;



其中, C 通常成为一个常量表达式。



但如果你说

 表达式来; Func键< INT>> ; EX = Expression.Lambda(...的东西,使用X ...); 



,编译器不知道你正在做的事情需要它吊起X; x不是lambda表达式中。如果您使用的工厂,编译器假定你知道你用它改写周围做什么,不乱。你必须自己扯起了。


I have a function which creates a delegate using expression trees. Within this expression I use a variable captured from multiple parameters passed in to the function. The actual expression tree is rather large so as an example:

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 then invoke this method from another method before passing that function to another function to use. Once that's all done I want to access the content of parents which gets updated within the expression tree.

Everything seems to compile, and my expression looks ok, but when I run it I appear (although I can't really be sure) to be getting null reference exceptions when accessing the parents variable (inside the expression/closure).

I guess I'd like to know if I'm doing something wrong or whether this is possible as well as tips for understanding what's going on. 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?

Thanks, Mark

解决方案

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?

It looks like you are building the expression tree lambda yourself, by "manually" calling the factory methods. The compiler has no idea that that's what you're doing; it just sees method calls. If you want locals to be hoisted then you're going to have to either (1) get the compiler to do it for you, by making it rewrite the lambda, or (2) hoist 'em yourself.

That is:

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

the compiler rewrites the lambda and hoists it for you, as though you'd said:

Closure c = new Closure();
c.x = 123;
Expression<Func<int>> ex = ()=>c.x; 

Where c typically becomes a Constant expression.

But if you say

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

the compiler has no idea that you're doing something where it needs to hoist x; x is not inside a lambda expression. If you're using the factories, the compiler assumes you know what you're doing and doesn't mess around with rewriting it. You'll have to hoist it yourself.

这篇关于问题在C#中的表达闭包变量捕获的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆