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

时间:2017-09-21 10:00:17

标签: c# linq linq-expressions

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

通过'局部变量'在这里,我不是指关闭。我指的是c#表达式树中特定于块的本地变量。目前,我有一个非常奇怪的情况,一个表达式树工作,另一个抛出异常:

  

未处理的类型' System.InvalidOperationException'发生在System.Core.dll

中      

附加信息:变量' num'类型' System.Int32'引用范围'',但未定义

工作代码编译自:

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:
    }
}

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

  

未处理的类型&#39; System.InvalidOperationException&#39;发生在System.Core.dll中   附加信息:变量&#39; num&#39;类型&#39; System.Int32&#39;引用范围&#39;&#39;,但未定义

这里真正令人困惑的是,唯一的区别是由随机{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#代码,因为虽然我被声明了两次,但它被声明为它 当地范围。我的编译器试图通过编译为:

来解释这个问题
*.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:
    }
}

有关如何处理此事的任何建议?我确信我完全以错误的方式处理这些局部变量。

1 个答案:

答案 0 :(得分:-1)

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