【问题标题】:For loop counter variable scope seems to have a dual personality? [duplicate]for循环计数器变量作用域似乎有双重人格? [复制]
【发布时间】:2014-01-08 19:51:42
【问题描述】:

以下代码在 Visual Studio 2012 中产生此错误; “不能在这个范围内声明一个名为‘x’的局部变量,因为它会给‘x’赋予不同的含义,而‘x’已经在‘子’范围内用来表示其他东西”

for (int x = 0; x < 9; x++) 
  {
     //something
  }
int x = 0;

但是。当如下修改时,我收到此错误; “当前上下文中不存在名称‘x’”

for (int x = 0; x < 9; x++) 
  {
     //something
  }
x = 0;

这是一个巨大的矛盾还是我错过了什么?

【问题讨论】:

  • Eric Lippert 有一篇关于这个的帖子...
  • @usr 这是一个系列。 Part 1Part 2。要回答OP的问题,不,这不是矛盾。引用 Eric 的链接文章,关键在于,“理解范围和声明空间之间的区别至关重要。”
  • 据我了解,第一个声明在任何版本的 VS 中都会出错。因为在 .NET (OOPS) 中,声明范围与顺序/顺序无关。

标签: c# scope


【解决方案1】:

到目前为止,除了 Rik 之外,没有人指出正确的答案。

再次仔细阅读错误消息。他们清楚地解释了错误。第一个错误是:

不能在此范围内声明名为“x”的局部变量,因为它会给“x”赋予不同的含义,后者已在“子”范围内用于表示其他内容

实际上阅读错误信息。它说用同一个名字来表示两个不同的东西是违法的。该错误与外部x 本身的范围无关;这与x相同的外部范围中用于表示两件事这一事实有关。

正如 Rik 所指出的,这条规则的目的是避免开发人员对x 的含义感到困惑的情况。一个给定的名称在整个块中几乎总是意味着相同的东西。 (有一些微妙的例外,但我们今天不讨论这些例外。)这条规则还有助于防止由于在方法中重新排序语句而引入的错误,从而巧妙地改变名称的含义。如果名称的含义在一个块中是不变的,则可以放心地在该块中进行代码编辑。

许多答案说范围不允许重叠。是的,他们是。 局部变量范围不允许重叠,但范围允许重叠。例如:

class C
{
    int x;
    void M()
    {
        int y = this.x;
        for(int x = 0; x < 10; ++x) {}
    }
}

完全合法,即使范围内同时存在两个名为 x 的东西。但这不合法:

class C
{
    int x;
    void M()
    {
        int y = x; // Means this.x
        for(int x = 0; x < 10; ++x) {} // means local x
    }
}

现在简单的名称x 意味着M 体内的两个不同的东西,而 是非法的。同样,请确保您理解这一点:在同一范围内使用相同的名称表示两个事物是非法的。重叠范围是非法的。

现在你的第二个错误:

“当前上下文中不存在名称‘x’”

名称x 仅在for 语句中有效。 for 声明:

for (declarations ; condition ; increment ) body

在逻辑上等价于(模中断和继续行为)

{
    declarations;
    while(condition)
    {
        body
        increment
    } 
}

注意外面的大括号。该声明中的任何内容都可以在整个条件、正文或增量中使用,但不在外部范围内。

【讨论】:

  • 天啊.. 我从没想过这种情况会这么具体。你解释得非常简单。谢谢埃里克!
【解决方案2】:

第一个是错误,因为它相当于这样:

int x;
for (int x = 0; x < 9; x++) 
{
   //something
   // 'x' is ambiguous here
}
x = 0;

变量声明在 C# 中的工作方式,与您的第一个示例相同。

第二个是错误,因为循环中定义的'x'变量只在循环中有效。

【讨论】:

  • 所以你的意思是不管声明发生在哪里,它总是放在方法的顶部,对吧?
  • 有点。在声明变量之前不能使用它,但是你声明的名称是保留的,就好像它是在作用域的顶部声明的一样。
  • 这里违反的规则与外部 x 在范围内的位置无关!例如考虑class C { int x; void M() { int y = x; for(int x = 0; ; ) {} }。这也是非法的,出于同样的原因。但它与外部x的范围无关!考虑class C { int x; void M() { int y = this.x; for(int x = 0; ; ) {} } 这是完全合法的,即使外部x 始终在范围内!这里的违规是 simple name x 不得用于表示同一范围内的两个不同事物,而不是范围重叠。范围可以重叠。
  • 这就是我试图在这里得到的,尤其是当您查看我之前的评论时:“您声明的 name 是保留的”。这是我费心写评论的乳清:回答关于声明位置无关紧要的问题。这很重要;范围确实发生了变化,因为变量在声明之前不在范围内。但原始问题中的问题与变量范围无关:它与命名冲突及其产生的歧义有关。
【解决方案3】:

C# 阻止您创建一个容易混淆x 实际指的是什么的混乱情况。

【讨论】:

    【解决方案4】:

    这并不矛盾。您在for 中定义的int x 的作用域是for 循环,意思是:

    for (int x = 0; x < 9; x++) 
    {
        //x is only alive here.
    }
    
    //you can't use it here.
    

    但是您不能在父范围(即方法范围)中创建另一个x 变量:

    public void MyMethod()
    {
       int x = 0; //method-scoped variable.
    
        for (int x = 0; x < 9; x++)  //for-scoped variable, with the same name, invalid.
        {
            //here you have 2 "x", which one to use? invalid.
        }
    
       //the first x is available here
    }
    

    【讨论】:

      【解决方案5】:

      这是由于子范围。

      由于i's 都在同一范围内,因此以下操作无效

      for (int i = 0; i < 100; i++)
      {
          Console.WriteLine(i);
      }
      
      int i = 10;
      Console.WriteLine(i);
      

      以下也不起作用,因为i's 仍在同一范围内

      {
          for (int i = 0; i < 100; i++)
          {
              Console.WriteLine(i);
          }
      }
      int i = 10;
      Console.WriteLine(i);
      

      以下操作就可以了

      {
          for (int i = 0; i < 100; i++)
          {
              Console.WriteLine(i);
          }
      }
      {
          int i = 10;
          Console.WriteLine(i);
      }
      

      【讨论】:

      • 这里没有解释为什么
      • 你还需要知道 for 循环被视为整个事物周围都有“不可见的大括号”。来自stackoverflow.com/questions/1196941/…
      • 由于子范围,但您没有解释正在产生的实际错误。请参阅我对乔尔回答的评论。
      【解决方案6】:

      用大括号括起来的一系列语句构成一个代码块。方法体是代码块的一个示例。代码块通常跟在控制语句之后。在代码块中声明的变量或常量仅对同一代码块中的语句可用。

      查看此链接:http://msdn.microsoft.com/en-us/library/ms173143%28v=vs.80%29.aspx

      这样做:

      for (int x = 0; x < 9; x++) 
        {
           //something
        }
      x = 0;
      

      被语义分析器检测为错误,因为 x 在 for 循环之外不再可用。

      尽管当您在内部块内部执行 int x 并在内部块外部声明 int x 时,编译器只会警告您语义中可能存在的错误。

      for (int x = 0; x < 9; x++) 
        {
           //something
        }
      
      //theoretically allowed, but the C# compiler identifies it as an error.
      int x = 0; //caution x declare before
      

      如果你对此感兴趣,解释很简单:

      如语言规范第 3.7 节所述。 “在局部变量声明 (8.5.1) 中声明的局部变量的范围是发生声明的块”。

      因此,x 的范围是您声明它的整个函数,这意味着在 for 循环之外的声明/使用是重复使用,因此是不允许的。

      此行为旨在减少不正确地重复使用变量名称(例如在剪切和粘贴中)的可能性。

      问候。

      【讨论】:

      • 第二个示例不会导致编译器警告,它会导致编译器错误。这实际上是一个显着的差异。
      • 非常准确地说,int x = 0; 在您的第一个示例中位于花括号之外,因此计算花括号不是关键。
      【解决方案7】:

      变量 x 是我们的作用域,因为它是在循环中声明的。如果你还是想再次使用相同的变量,试试这个 - (虽然不推荐 - 标准)

      int x = 0;
      for (x = 0; x < 9; x++){
      //something
      }
      x = 0;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-03-26
        • 1970-01-01
        • 2018-05-29
        • 2013-09-10
        • 1970-01-01
        • 1970-01-01
        • 2020-04-05
        相关资源
        最近更新 更多