[英]local variable scope in linq anonymous method ( closure)
Linq Query中声明的局部变量的范围是什么。
我正在编写以下代码
static void Evaluate()
{
var listNumbers = Enumerable.Range(1, 10).Select(i => i);
int i = 10;
}
编译器标记的错误在行int i = 10,说明
A local variable named 'i' cannot be declared in this scope because it would give a different meaning to 'i', which is already used in a 'child' scope to denote something else
我无法理解为什么会出现这个错误。
我的理解是, i
将在第一行之后(在foreach循环中)超出范围。 所以i
可以再次宣布。
实际行为是i
在第一行(在foreach循环中)之后无法访问,这是正确的。 但i
不能再宣布了。 这看起来很奇怪。
编辑这是基于安德拉斯的回应的以下问题。 答案非常好,但会引起进一步的质疑。
static void Evaluate3()
{
var listNumbers = Enumerable.Range(1, 10).Select(i => i);
var listNumbers1 = Enumerable.Range(1, 10).Select(i => i);
}
基于函数的逻辑评估.Select(i => i)和int i = 10,两者都是函数块的局部因而是复杂性错误。
函数Evaluate3不应该编译,因为方法块中有两个i,但它正在成功编译而没有任何警告/错误。
问题,Evaluate和Evaluate3都不应该编译,或者两者都应该编译。
这里要注意的关键事实是声明:
int i;
... 从头到尾贯穿整个封闭范围 - 不仅仅是从声明它的位置开始生效。 在.Net中,局部变量的声明只是编译器为整个范围保留该名称和本地的指令。 这意味着一旦声明,它就已经为所有线路保留了之前和之后 。
实际上,这意味着您应该将Evaluate
实际读作:
static void Evaluate()
{
int i;
var listNumbers = Enumerable.Range(1, 10).Select(i => i);
i = 10;
}
如果你相应地编写了你的方法,你会发现编译器错误发生在lambda声明上 - 这是完全合理的。 值得庆幸的是,从人类的角度来看,C#编译器非常聪明,认识到代码的排序对我们很重要,它实际上将编译器错误分配给第二个或后续声明中的任何源代码行; 因此,为什么在你的Evaluate
版本中,它发生在行int i = 10;
。 有了函数本地i
的实际生命周期的知识,编译器是正确的:使用i
会与早期在lambda中使用i
冲突。
您可以使用显式范围来避免这种情况:
static void Evaluate()
{
var listNumbers = Enumerable.Range(1, 10).Select(i => i);
{
int i = 10;
}
}
在的情况下Evaluate3
你只需注意的是,尽管这两个lambda表达式共享父功能范围,他们也有他们自己的,它在那里,他们i
s的声明-这就是为什么他们不互相干扰(他们是,实际上,兄弟范围)。
顺便说一下, Evaluate
和Evaluate3
最终可以简化为:
static void Evaluate()
{
{
int i;
}
int i; //<-- error
}
static void Evaluate3()
{
{
int i;
}
{
int i;
}
//fine here - both i's are in different scopes.
}
实际上这是第二种情况,我之前使用过显式范围 - 也就是说,在同一函数中的不同范围内,其中i
实际上每种范围都有不同的类型。 就像我说的 - 我再也没有这样做过,而且有问题的代码已不再存在了:)
从规格 :
The scope of a local variable declared in a local-variable-declaration is the block in which the declaration occurs. It is an error to refer to a local variable in a textual position that precedes the local-variable-declarator of the local variable.
你的lambda i => i
在本地变量int i = 10
的范围内,即使它是事先声明的。 而不是因为你在声明它之前使用i
而引发错误,编译器有助于指出你已经使用i
来引用别的东西并且这个声明会改变它。
编辑:更新后:
在第一种情况下,你的第一个i
被包含在lambda中,但你的第二个i
包含整个Evaluate
方法, 包括lambda - 因此你得到了错误。
在第二种情况下,你的第一个i
被包含在它的lambda中,你的第二个i
被包含在它的 lambda中 - i
都不在另一个范围内,因此没有错误。
您的段落“基于......两者的逻辑,是功能块的本地...”是不正确的 - 第一个i
不是功能块的本地,而是lambda。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.