在绑定到块的 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 引用了一个不同的对象但同名参数表达式,这与块中的参数表达式不同。同名参数表达式不一定是相同的参数表达式!
我的问题是,尽管函数参数变量工作得很好,但我无法在不抛出异常的情况下使 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 引用了一个不同的对象但同名参数表达式,这与块中的参数表达式不同。同名参数表达式不一定是相同的参数表达式!