构建LINQ表达式树:如何获取作用域中的变量

28

我正在构建一个LINQ表达式树,但由于据称本地变量$var1超出了范围而无法编译:

变量“”类型为“System.Object”,在作用域“”中引用,但未定义

这是表达式树:

.Block() {
    $var1;
    .If ($n.Property1 == null) {
        .Block() {
            $var1 = null;
            .Return #Label1 { }
        }
    } .Else {
        .Default(System.Void)
    };
    $var1 = (System.Object)($n.Property1).Length;
    .Label
    .LabelTarget #Label1:;
    $var1
}
以下代码负责构建树。它是更大的东西的一部分,因此我不希望从这个示例中完全清楚其目的。
MemberExpression sourceExpression = ...;

List<Expression> expressions = new List<Expression>();
LabelTarget returnTarget = Expression.Label();
ParameterExpression resultVariable = Expression.Variable(typeof(object));

expressions.Add(resultVariable);

expressions.Add(
    Expression.IfThen(
        Expression.Equal(sourceExpression, Expression.Constant(null)),
        Expression.Block(
            Expression.Assign(resultVariable, Expression.Constant(null)),
            Expression.Return(returnTarget))));

expressions.Add(
    Expression.Assign(
        resultVariable,
        Expression.Convert(sourceExpression, typeof(object))));

expressions.Add(Expression.Label(returnTarget));
expressions.Add(resultVariable);

Expression finalExpression = Expression.Block(expressions);
object result = Expression.Lambda<Func<object>>(finalExpression).Compile()();

所以问题是:我如何使局部变量进入作用域,以便表达式可以成功编译?

1个回答

47

您将 Expression.Variable 添加到块中的“普通”表达式列表中 - 您应该使用指定要为块声明的变量的重载版本

Expression finalExpression = Expression.Block(new[] { resultVariable },
                                              expressions);

(并删除对expressions.Add(resultVariable);的调用)


谢谢Jon,这个可行!解决了这个问题后发现了第二个相似的问题。sourceExpression变量的赋值使表达式编译器抛出异常:"变量'n'是'TestClass'类型,引用自作用域'',但未定义"。 - Sandor Drieënhuizen
1
再次感谢您的帮助。这个问题与我正在写的博客文章密切相关,该文章位于http://blog.subspace.nl/post/Getting-rid-of-null-checks-in-property-chains.aspx,可能会引起兴趣。 - Sandor Drieënhuizen
谢谢您提供的链接,正是我需要了解 lambda 参数与块作用域变量的区别。 - tuespetre

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接