Variable declared in for-loop is local variable?

2019-03-08 09:21发布

I have been using C# for quite a long time but never realised the following:

 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
 }

So why can I not use the value of 'i' outside of the for block if it does not allow me to declare a variable with this name?

I thought that the iterator variable used by a for-loop is valid only in its scope.

9条回答
Luminary・发光体
2楼-- · 2019-03-08 09:33

The easiest way to think about this is to move the outer declaration of I to above the loop. It should become obvious then.

It's the same scope either way, therefore can't be done.

查看更多
在下西门庆
3楼-- · 2019-03-08 09:37

There is a way of declaring and using i inside the method after the loop:

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

    }

    {
        int i = 4;
        int A = i;
    }
}

You can do this in Java (it might originate from C I'm not sure). It is of course a bit messy for the sake of a variable name.

查看更多
叛逆
4楼-- · 2019-03-08 09:37

Kommer's answer is technically correct. Let me paraphrase it with a vivid blind-screen metaphor.

There is a one way blind screen between the for-block and the enclosing outer block such that the code from within the for-block can see the outer code but the code in the outer block cannot see the code inside.

Since the outer code cannot see inside , it cannot use anything declared inside. But since the code in the for-block can see both inside and outside , a variable declared at both places cannot be used unambiguously by name.

So either you don't see it , or you C# !

查看更多
老娘就宠你
5楼-- · 2019-03-08 09:38

The reason you are not allowed to define a variable with the same name in both the for-loop as well as outside the for-loop is because variables in the outer-scope are valid in the inner-scope. Meaning that there would be two 'i' variables within the for-loop if this was allowed.

See: MSDN Scopes

Specifically:

The scope of a local variable declared in a local-variable-declaration (Section 8.5.1) is the block in which the declaration occurs.

and

The scope of a local variable declared in a for-initializer of a for statement (Section 8.8.3) is the for-initializer, the for-condition, the for-iterator, and the contained statement of the for statement.

And also: Local variable declarations (Section 8.5.1 of the C# specification)

Specifically:

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. Within the scope of a local variable, it is a compile-time error to declare another local variable or constant with the same name.

(Emphasis mine.)

Which means that the scope of the i inside your for-loop, is the for-loop. Whereas the scope of the i outside of your for-loop is the entire main method plus the for-loop. Meaning you'd have two occurrences of i inside the loop which is invalid according to the above.

The reason why you're not allowed to do int A = i; is because int i is only scoped for use within the for loop. Thus it is no longer accessible outside of the for loop.

As you can see both of these issues are a result of scoping; the first issue (int i = 4;) would result in two i variables within the for loop scope. Whereas int A = i; would result in access to a variable that is out of scope.

What you could do instead is declare i to be scoped to the entire method, and then use it in both the method as well as the for-loop scope. This will avoid breaking either rule.

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;
}

EDIT:

The C# compiler could of course be changed to allow this code to compile quite validly. After all this is valid:

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

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

But would it really be beneficial to your code readability and maintainability to be able to write code such as:

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);
}

Think about the potential for mistakes here, does the last i print out 0 or 4? Now this is a very small example, one which is quite easy to follow and track but it is definitely a lot less maintainable and readable than having declared the outer i by a different name.

N.B:

Please note, C#'s scoping rules differ from C++'s scoping rules. In C++ variables are only in scope from where they are declared until the end of the block. Which would make your code a valid construct in C++.

查看更多
贪生不怕死
6楼-- · 2019-03-08 09:46

J.Kommer's answer is correct: briefly, it is illegal for a local variable to be declared in a local variable declaration space that overlaps another local variable declaration space that has a local of the same name.

There is an additional rule of C# that is violated here as well. The additional rule is that it is illegal for a simple name to be used to refer to two different entities inside two different overlapping local variable declaration spaces. So not only is your example illegal, this is illegal too:

class C
{
    int x;
    void M()
    {
        int y = x;
        if(whatever)
        {
            int x = 123;

Because now the simple name "x" has been used inside the local variable declaration space of "y" to mean two different things -- "this.x" and the local "x".

See http://blogs.msdn.com/b/ericlippert/archive/tags/simple+names/ for more analysis of these issues.

查看更多
看我几分像从前
7楼-- · 2019-03-08 09:47

In addition to J.Kommer's answer (+1 btw). There's this in the standard for NET scope:

block If you declare a variable within a block construct such as an If statement, that variable's scope is only until the end of the block. The lifetime is until the procedure ends.

Procedure If you declare a variable within a procedure, but outside of any If statement, the scope is until the End Sub or End Function. The lifetime of the variable is until the procedures ends.

Thus the int i decalared within the for loop header will be in scope only during the for loop block, BUT it's lifetime lasts until the Main() code completes.

查看更多
登录 后发表回答