在绑定到块的 C# 表达式树中声明局部变量

declaring local variables in c# expression trees bound to a block

我的问题是,尽管函数参数变量工作得很好,但我无法在不抛出异常的情况下使 c# 表达式树(例如 System.Linq.Expressions)中的块的局部变量工作。

这里的'local variables',我指的不是闭包。我的意思是特定于 c# 表达式树中的块的变量。目前,我有一个非常奇怪的情况,其中一个表达式树有效,另一个抛出异常:

An unhandled exception of type 'System.InvalidOperationException' occurred in System.Core.dll

Additional information: variable 'num' of type 'System.Int32' referenced from scope '', but it is not defined

工作代码编译自:

public static int Assign ()
{
    int num;
    int num2;
    num = 1;
    num2 = 2;
    return num + num2;
}

到表达式树(调试视图):

.Lambda #Lambda1<System.Func`1[System.Int32]>() {
    .Block(
        System.Int32 $num,
        System.Int32 $num2) {
        0;
        0;
        $num = 1;
        $num2 = 2;
        .Return returnLabel { $num + $num2 };
        .Label
            0
        .LabelTarget returnLabel:
    }
}

这工作正常。但是,当我的编译器尝试编译时:

public static int Assign ()
{
    int num = 1;
    int num2 = 2;
    return num + num2;
}

如:

.Lambda #Lambda1<System.Func`1[System.Int32]>() {
    .Block(
        System.Int32 $num,
        System.Int32 $num2) {
        $num = 1;
        $num2 = 2;
        .Return returnLabel { $num + $num2 };
        .Label
            0
        .LabelTarget returnLabel:
    }
}

此块表达式抛出无效操作异常 -

An unhandled exception of type 'System.InvalidOperationException' occurred in System.Core.dll Additional information: variable 'num' of type 'System.Int32' referenced from scope '', but it is not defined

这里真正令人困惑的是,唯一的区别是由随机 {0} - System.Linq.Expressions.Expression.Constant(0) 表达式引起的,这似乎使错误消失了(它们存在的原因是

具体来说,lambda中定义的参数不会出现这个问题 表达式,例如,编译器处理:

public static Crappier<int> FieldAssign(int i, Crap thing)
        {
            thing.field = i;
            return new Crappier<int>(); ;
        }

输出表达式树很好:

.Lambda #Lambda1<System.Func`3[System.Int32,Sulieman.Crap,Sulieman.Crappier`1[System.Int32]]>(
    System.Int32 $i,
    Sulieman.Crap $thing) {
    .Block() {
        $thing.field = $i;
        .Return returnLabel { .New Sulieman.Crappier`1[System.Int32]() };
        .Label
            null
        .LabelTarget returnLabel:
    }
}

但是,我特别想要绑定到一个块的变量。这样做的原因是在代码中:

for (int i = 0; i < 3; i++) {
    Console.WriteLine("hello");
}

for (int i = 0; i < 3; i++) {
    Console.WriteLine("world");
}

这是有效的 c# 代码,因为虽然 i 被声明了两次,但它被声明为 本地范围。我的编译器试图通过编译来解决这个问题:

*.Lambda #Lambda1<System.Action>() {
    .Block() {
        .Block(System.Int32 $i) {
            $i = 0;
            .Loop .LabelTarget forContinueLabel: {
                .If ($i < 3) {
                    .Block() {
                        .Block() {
                            .Call System.Console.WriteLine("hello")
                        };
                        $i++
                    }
                } .Else {
                    .Break forBreakLabel { }
                }
            }
            .LabelTarget forBreakLabel:
        };
        .Block(System.Int32 $i) {
            $i = 0;
            .Loop .LabelTarget forContinueLabel: {
                .If ($i < 3) {
                    .Block() {
                        .Block() {
                            .Call System.Console.WriteLine("world")
                        };
                        $i++
                    }
                } .Else {
                    .Break forBreakLabel { }
                }
            }
            .LabelTarget forBreakLabel:
        };
        .Label
            3
        .LabelTarget returnLabel:
    }
}

关于如何处理这个问题有什么建议吗?我相当确定我正在以完全错误的方式处理这些局部变量。

没关系 - 这是一个令人讨厌的错误,其中赋值 $num 引用了一个不同的对象但同名参数表达式,这与块中的参数表达式不同。同名参数表达式不一定是相同的参数表达式!