Monday, February 04, 2013

Foreach Behavior With Anonymous Methods and Captured Value

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: Inline image 1

Posted via email from Jasper-Net