6

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,i 都是函数块的局部,因此会出现复杂错误。

函数 Evaluate3 不应该编译,因为方法块中有两个 i,但它编译成功,没有任何警告/错误。

问题,Evaluate 和 Evaluate3 都不应该编译,或者两者都应该编译。

4

2 回答 2

8

这里要注意的关键事实是声明:

int i;

...从开始到结束在整个封闭范围内生效- 而不仅仅是从声明的那一点开始。在 .Net 中,局部变量的声明只是对编译器的一条指令,用于为整个范围保留该名称和局部变量。这意味着一旦它被声明,它就已经为before 和 after的所有行保留了。

实际上,这意味着您实际上应该阅读Evaluate为:

static void Evaluate()  
{  
  int i;  
  var listNumbers = Enumerable.Range(1, 10).Select(i => i);  
  i = 10;
} 

如果您确实相应地编写了您的方法,您会看到编译器错误发生在 lambda 声明上——这是完全合理的。值得庆幸的是,从人类的角度来看,C# 编译器足够聪明,可以认识到代码的顺序对我们很重要,它实际上会将编译器错误分配给第二个或后续声明的源代码行;因此为什么在你的版本中Evaluate它发生就行了int i = 10;。知道了函数 local 的实际生命周期i,编译器是正确的:ithere的使用i与lambda 中的早期使用冲突。

您可以使用显式范围来避免这种情况:

static void Evaluate()  
{
  var listNumbers = Enumerable.Range(1, 10).Select(i => i);
  {
    int i = 10;
  }
}

在您的情况下,Evaluate3请注意,虽然两个 lambda 共享父函数范围,但它们也有自己的,并且在那里声明了它们i的 s - 这就是它们不相互干扰的原因(实际上它们是, 同级作用域)。

顺便说一句EvaluateEvaluate3最终可以简化为:

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实际上每个函数都有不同的类型。就像我说的那样 - 我再也没有做过,有问题的代码不再存在:)

于 2012-05-09T14:43:44.787 回答
1

规格

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的本地。

于 2012-05-09T14:29:20.960 回答