Translate

Monday, June 16, 2014

C# captured variables made simple (aka C# closures)

What do you think the following piece of code will do?

using System;
using System.Collections.Generic;
 
internal class Test
{
    private static void Main()
    {
        var actions = new List<Action>();
  
        for (int i = 0; i < 3; i++)
        {
            actions.Add(() => Console.WriteLine(i));
        }
     
        foreach (Action action in actions)
        {
            CallAction(action);
        }
    }
 
    public static void CallAction(Action action)
    {
        action();
    }
}

You might expect it to print 0 1 2, but what it actually does is print 3, three times.









The reason for this happening is that a lambda expression retains the last value of the variable. This phenomenon is called closure in computer science. In .net its called a captured variable. The code above can be fixed as shown below. What we are doing is that for every iteration we are declaring a new variable.


using System;
using System.Collections.Generic;
 
internal class Test
{
    private static void Main()
    {
        var actions = new List<Action>();
 
        for (int i = 0; i < 3; i++)
        {
            int temp = i;
            actions.Add(() => Console.WriteLine(temp));
        }
 
        foreach (Action action in actions)
        {
            CallAction(action);
        }
    }
 
    public static void CallAction(Action action)
    {
        action();
    }
}














However, you must remember, if you change the value of the variable temp, after its used inside the lambda expression, then you will get that latest value of temp.

No comments:

Post a Comment

Comments will appear once they have been approved by the moderator