1

Possible Duplicate:
Why can’t a duplicate variable name be declared in a nested local scope?

I noticed that the following code didn't compile. Quick fix was to recall the outer variable thing to something else but then I started to think and realized that the internal scope should end within the foreach loop. I sure can't use the internal variable outside it.

Shouldn't I be able to reuse the name thing outside the loop? Why?

String aggregate = String.Empty;
foreach (Thing thing in things)
  aggregate += thing.Value;

Thing thing = new Thing();
Community
  • 1
  • 1

2 Answers2

6

Shouldn't I be able to reuse the name thing outside the loop? Why?

The problem is that the scope of the variable in the last line extends up... it covers the whole block. So the problem is actually that you can't declare the thing variable for the loop as that clashes with another variable which is already in scope.

From section 8.5.1 of the C# 4 spec:

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-declaration 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.

That last sentence is the one your code is violating.

Just use different names.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 1
    Wow, I learned something there. Thanks Jon! On that note, are you implying that even if a variable is **coded** on the tenth line of the scope, in the IL it's **declared** at the top? – Mike Perrenoud Oct 18 '12 at 17:25
  • 1
    +1... Do you count how many times you answered this one already :) – Alexei Levenkov Oct 18 '12 at 17:27
  • @BigM Kinda, sorta. I may be wrong but: the generated IL will have different values for say its `stdloc.#` instructions but otherwise it's identical. `object B; object A = new object(); B = new Object()` results in IL `newobj; stloc.1; newobj; stloc.0` whereas `object A = new object(); object B = new object()` results in IL `newobj; stloc.0; newobj; stloc.1;` There is no explicit "declaration at the top" in IL (AFAIK), it just directly references the location numbers in-line. I guess you could look at that hard-coding of location numbers as equivalent to being declared "at the top" sort of. – Chris Sinclair Oct 18 '12 at 17:37
  • 1
    @BigM: No, it's definitely declared on the tenth line - but its scope extends to the start of the block. – Jon Skeet Oct 18 '12 at 17:52
  • @JonSkeet, thanks, I apprecaite it! – Mike Perrenoud Oct 18 '12 at 17:59
0

In fact, as surprising it might feel, the variable's scope is wider than what you'd expect. Give this code a try.

String aggregate = String.Empty;
foreach (Thing thing in things)
  aggregate += thing.Value;
foreach (Thing thing in things)
  aggregate += thing.Value;

It'll compile just fine. However, if you declare the thing outside as you did, the declaration span is outwards. It gets me too, sometime. :)

Konrad Viltersten
  • 36,151
  • 76
  • 250
  • 438