在for循环中声明的变量是局部变量?

Joh*_*n V 134 c# variables scope

我一直在使用C#很长时间但从未意识到以下情况:

 public static void Main()
 {
     for (int i = 0; i < 5; i++)
     {

     }

     int i = 4;  //cannot declare as 'i' is declared in child scope                
     int A = i;  //cannot assign as 'i' does not exist in this context
 }
Run Code Online (Sandbox Code Playgroud)

那么,为什么我不能在for块之外使用'i'的值,如果它不允许我声明一个带有这个名字的变量?

我认为for循环使用的迭代器变量仅在其范围内有效.

Joh*_*mer 119

究其原因,你不允许定义具有相同名称的变量都在for循环以及外部for循环是因为在外部范围的变量在内部范围内有效.这意味着如果允许的话,for循环中会有两个'i'变量.

请参阅:MSDN范围

特别:

在local-variable-declaration(第8.5.1节)中声明的局部变量的范围是声明发生的块.

在换初始化for语句的(第8.8.3)声明的局部变量的范围是for-初始化,for条件所示,将迭代器,和for语句所包含的语句.

还有:局部变量声明(C#规范的第8.5.1节)

特别:

在local-variable-declaration中声明的局部变量的范围是声明发生的块.在局部变量的local-variable-declarator之前的文本位置引用局部变量是错误的.在局部变量的范围内,声明另一个具有相同名称的局部变量或常量是编译时错误.

(强调我的.)

这意味着i你的for循环内部的范围是for循环.而ifor循环外部的范围是整个main方法加上 for循环.这意味着你i在循环中有两次出现,根据上面的说法是无效的.

你不被允许这样做int A = i;的原因int i是因为它只是在for循环中使用的范围.因此,它不再可以在for循环之外访问.

正如您所看到的,这两个问题都是范围界定的结果; 第一个问题(int i = 4;)将导致循环范围i内的两个变量for.而int A = i;导致访问超出范围的变量.

您可以做的是声明i为整个方法的范围,然后在方法和for循环范围中使用它.这样可以避免违反任何规则.

public static void Main()
{
    int i;

    for (i = 0; i < 5; i++)
    {

    }

    // 'i' is only declared in the method scope now, 
    // no longer in the child scope -> valid.
    i = 4;

    // 'i' is declared in the method's scope -> valid. 
    int A = i;
}
Run Code Online (Sandbox Code Playgroud)

编辑:

当然可以更改C#编译器以允许此代码非常有效地编译.毕竟这是有效的:

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

for (int i = 5; i > 0; i--)
{
    Console.WriteLine(i);
}
Run Code Online (Sandbox Code Playgroud)

但是,为了能够编写代码,您的代码可读性和可维护性是否真的有益:

public static void Main()
{
    int i = 4;

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

    for (int i = 5; i > 0; i--)
    {
        Console.WriteLine(i);
    }

    Console.WriteLine(i);
}
Run Code Online (Sandbox Code Playgroud)

想想这里可能出现的错误,最后i打印出来的是0还是4?现在这是一个非常小的例子,一个非常容易跟踪和跟踪的例子,但它肯定比i用不同的名称声明外部要少得多,可维护性和可读性.

注意:

请注意,C#的范围规则与C++的范围规则不同.在C++中,变量仅在声明它们的范围内,直到块的结尾.这将使您的代码成为C++中的有效构造.

  • 或许,为了完整起见,这个答案应该指出C#范围规则在这种情况下与C++的范围规则__different__.在C++中,变量仅在声明它们的范围内,直到块的结尾(参见http://msdn.microsoft.com/en-us/library/b7kfh662(v=vs.80).aspx). (9认同)
  • 好吧,如果我在for语句之后声明'A',它在for循环中无效,因为它稍后被声明.这就是为什么我不明白为什么不能使用相同的名称. (2认同)
  • 请注意,Java采用C++和C#之间的中间方法:因为它的OP示例在Java中是有效的,但如果外部`i`定义在for循环之前被移动,则内部`i`定义将被标记为无效. (2认同)

Eri*_*ert 29

J.Kommer的答案是正确的:简单地说,它是非法的局部变量在声明局部变量声明空间重叠的另一个局部变量声明空间,有一个本地的同名.

此处还有一个违反C#的附加规则.附加规则是,使用简单名称来引用两个不同的重叠局部变量声明空间内的两个不同实体是非法的.所以不仅你的例子是非法的,这也是非法的:

class C
{
    int x;
    void M()
    {
        int y = x;
        if(whatever)
        {
            int x = 123;
Run Code Online (Sandbox Code Playgroud)

因为现在简单的名称"x"已经在"y"的局部变量声明空间内使用,意味着两个不同的东西 - "this.x"和本地"x".

有关这些问题的更多分析,请参见http://blogs.msdn.com/b/ericlippert/archive/tags/simple+names/.

  • @Phil:正确.`this.x`不是*简单的名字*. (4认同)
  • 另外,有趣的是,当您进行更改`int y = this.x;`时,您的示例代码将被编译 (2认同)

Chr*_*s S 13

i在循环之后有一种在方法内部声明和使用的方法:

static void Main()
{
    for (int i = 0; i < 5; i++)
    {

    }

    {
        int i = 4;
        int A = i;
    }
}
Run Code Online (Sandbox Code Playgroud)

你可以用Java做到这一点(它可能来自C我不确定).为了变量名,它当然有点乱.


Wid*_*dor 7

如果你宣布i 之前你的for循环,你认为它应该仍然有效宣布它在循环中?

不,因为那时两者的范围会重叠.

至于无法做到int A=i;,那只是因为i它只存在于for循环中,就像它应该做的那样.


Chr*_*sBD 7

除了J.Kommer的回答(+1 btw).NET范围的标准中有这个:

block 如果在块构造(如If语句)中声明变量,则该变量的作用域仅在块结束之前.寿命一直持续到程序结束.

过程 如果在过程中声明变量,但在任何If语句之外,则作用域将在End Sub或End Function之前.变量的生命周期是程序结束.

因此,for循环标头中的int i decalared仅在for循环块期间在范围内,它的生命周期将持续到Main()代码完成为止.


And*_*ber 5

考虑这一点的最简单方法是将I的外部声明移到循环之上.那应该是显而易见的.

无论哪种方式都是相同的范围,因此无法完成.