5

I have this string array of names.

string[] someArray = { "Messi", "Ronaldo", "Bale", "Neymar", "Pele" };

foreach (string item in someArray)
  {
     Console.WriteLine(item);
  }

When I run in debug mode with breakpoint on foreach line, and using Step Into, string item is highlighted each time with each pass like it declares it again. I suppose it should highlight item only. Does this mean that with each time item is declared again?

Note: using VS 2012.

3
  • 2
    What would be your concern if it was? Commented May 23, 2015 at 1:14
  • 3
    I do not have any concern, just trying to understand what's going on. I am new in coding. If I understand code better, it gives me some confidence I can get it :) Commented May 23, 2015 at 1:47
  • Also, from what I was learning till now, variable is declared only once. However, this maybe be break of that rule (.net runtime gets rid of it)? Not a big deal, just trying to figure it out. Commented May 23, 2015 at 1:53

2 Answers 2

10

The answer here is subtle because the question is (accidentally) unclear. Let me clarify it by breaking it apart into multiple questions.

Is the loop variable logically redeclared every time I go through a foreach loop?

As the other answer correctly notes, in C# 5 and higher, yes. In C# 1 through 4, no.

What is the observable consequence of that change?

In C# 1 there is no way to tell the difference. (And the spec is actually unclear as to where the variable is declared.)

In C# 2 the team added closures in the form of anonymous methods. If there are multiple closures that capture a loop variable in C# 2, 3 and 4 they all capture the same variable, and they all see it mutate as the loop runs. This is almost never what you want.

In C# 5 we took the breaking change to say that a new loop variable is declared every time through the loop, and so each closure captures a different variable and therefore does not observe it changing.

Why does the debugger go back to the loop variable declaration every time I step through the loop?

To inform you that the loop variable is being mutated. If you have

IEnumerable<string> someCollection = whatever;
foreach(string item in someCollection)
{
    Console.WriteLine(item);
}

That is logically equivalent to

IEnumerable<string> someCollection = whatever;
{
    IEnumerator<string> enumerator = someCollection.GetEnumerator();
    try
    {
        while( enumerator.MoveNext() )
        {
            string item;  // In C# 4.0 and before, this is outside the while
            item = enumerator.Current;
            {
                Console.WriteLine(item);
            }
        }
    }
    finally
    {
        if (enumerator != null)
            ((IDisposable)enumerator).Dispose();
    }
}

If you were debugging around that expanded version of the code, you would see the debugger highlight the invocations of MoveNext and Current. Well, the debugger does the same thing in the compact form; when MoveNext is about to be called the debugger highlights the in, for lack of anything better to highlight. When Current is about to be called it highlights item. Again, what would be the better thing to highlight?

So the fact that the debugger highlights the variable has nothing to do with whether the variable is redeclared?

Correct. It highlights the variable when Current is about to be called, because that will mutate the variable. It mutates the variable regardless of whether it is a new variable, in C# 5, or the same variable as before, in C# 4.

I noticed that you changed my example to use a generic sequence rather than an array. Why did you do that?

Because if the C# compiler knows that the collection in the foreach is an array, it actually just generates a good old fashioned for loop rather than calling MoveNext and Current and all that. Doing so is typically faster and produces less collection pressure, so it's a win all around.

However, the C# team wants the debugging experience to feel the same regardless. So again, the code generator creates stepping points on in -- this time where the generated for's loop variable is mutated -- and again, on the code which mutates the foreach loop variable. That way the debugging experience is consistent.

Sign up to request clarification or add additional context in comments.

2 Comments

Ok, Thanks. This clears it a lot. I have only 1 month xp in programming, advanced topic for me.
@ExpertLoser: This is indeed a pretty advanced topic for a beginner. Your curiosity about figuring out how things work will be a great asset I'm sure! I am at present writing a series of videos for beginner C# programmers; if you have any insights as to what concepts are difficult for beginners, feel free to drop me a note at [email protected].
8

It depends on which version of C# you are targeting. In C# 5, it's a new variable. Before that, the variable was reused.

See Eric Lippert's blog post here: http://blogs.msdn.com/b/ericlippert/archive/2009/11/12/closing-over-the-loop-variable-considered-harmful.aspx

From the post:

UPDATE: We are taking the breaking change. In C# 5, the loop variable of a foreach will be logically inside the loop, and therefore closures will close over a fresh copy of the variable each time. The "for" loop will not be changed. We return you now to our original article.

1 Comment

Ok, so with each pass new variable declaration as I understand it?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.