问题与在c#表达闭合可变捕获(Issue with closure variable capture

2019-07-18 23:10发布

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

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();
}

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

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

我想我想知道如果我做错事或者这是否是可能的,以及对于理解发生了什么事情的提示。 我似乎没有能够找到方法中的任何悬挂(?)的局部变量,所以我想知道是否他们正在拍摄的呢?

谢谢,马克

Answer 1:

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

它看起来像你正在构建的表达式树拉姆达自己,通过“手动”调用工厂方法。 编译器有没有想法,那就是你在做什么; 因为它会把方法调用。 如果你想当地人将被吊起,然后你将不得不要么(1)让编译器为你做, 通过使改写拉姆达,或(2)你自己扯起他们。

那是:

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

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

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

其中c通常变得一常量表达式。

但如果你说

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

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



Answer 2:

我认为你正在寻找Expression.Quote ,它支持Lambda表达式变量捕获。 基本上,内LambdaExpression (将参考所捕获的变量)需要被包裹在一个Expression.Quote(...)调用。

例子和这里的讨论: 什么是Expression.Quote()做Expression.Constant()已经不能做什么?



文章来源: Issue with closure variable capture in c# expression