I was attending the TechDays 2013 in the Netherlands this week and I got an interesting quiz question presented. The question was: What is the output of the following progra
It is because it is a captured variable. Note that this used to also happen with foreach
, but that changed in C# 5. But to re-write your code to what you actually have:
class Program
{
delegate void Writer();
class CaptureContext { // generated by the compiler and named something
public int i; // truly horrible that is illegal in C#
public void DoStuff() {
Console.WriteLine(i);
}
}
static void Main(string[] args)
{
var writers = new List();
var ctx = new CaptureContext();
for (ctx.i = 0; ctx.i < 10; ctx.i++)
{
writers.Add(ctx.DoStuff);
}
foreach (Writer writer in writers)
{
writer();
}
}
}
As you can see: there is only one ctx
thus only one ctx.i
, and it is 10 by the time you foreach
over writers
.
Btw, if you want to make the old code work:
for (int tmp = 0; tmp < 10; tmp++)
{
int i = tmp;
writers.Add(delegate { Console.WriteLine(i); });
}
Basically, the capture-context is scoped at the same level as the variable; here the variable is scoped inside the loop, so this generates:
for (int tmp = 0; tmp < 10; tmp++)
{
var ctx = new CaptureContext();
ctx.i = tmp;
writers.Add(ctx.DoStuff);
}
Here each DoStuff
is on a different capture-context instance, so has a different and separate i
.