Recently I've been researching the behavior of the foreach loop for C# in 5.0 and earlier versions. Here's a snippet I was trying and getting different output in different versions of C#.
var values = new List<string>() { "Bob", "is", "stupid" };
var funcs = new List<Func<string>>();
foreach (var v in values)
funcs.Add(() => v);
foreach (var f in funcs)
Console.WriteLine(f());
Console.Read();
When I ran this code with Visual Studio 2010 I got the output as:
stupid stupid stupid
But when I tried the same code in Visual Studio 2012 the output was:
Bob is stupid
Which is the correct output as expected. I was wondering why this is. So I studied the implementation of the Foreach loop and found that the earlier versions of C# was designed to optimize the execution of Anonymous methods inside the foreach loop. The point is that Anonymous methods uses captured local variables. If a variable is declared locally then if your anonymous method is using an outer variable from a foreach implementation then the last updated value will be captured. Which is why I was getting the output of the program as "stupid stupid stupid" as this was the last value captured from the outer variable.
Now let's take a deep dive into captured values of variables in anonymous methods.
Outer variable: Any local variable, value parameter, or parameter array whose scope includes an anonymous method expression is called an outer variable of that anonymous-method-expression. In an instance of a function member of a class, the "this" value is considered a value parameter and is an outer variable of any anonymous-method-expression contained within that function member.
Captured value: When an outer variable is referenced by an anonymous method, the outer variable is said to have been captured by the anonymous method. Ordinarily, the lifetime of a local variable is limited to execution of the block or statement with which it is associated. However, the lifetime of a captured outer variable is extended at least until the delegate referring to the anonymous method becomes eligible for garbage collection.
Read more: C# Corner
QR: