Alex Rivera | Logout

How to tell a lambda function to capture a copy instead of a reference in C#?

Asked 2009-01-16T20:08:09.890
48

I've been learning C#, and I'm trying to understand lambdas. In this sample below, it prints out 10 ten times.

class Program
{
    delegate void Action();
    static void Main(string[] args)
    {
        List<Action> actions = new List<Action>();

        for (int i = 0; i < 10; ++i )
            actions.Add(()=>Console.WriteLine(i));

        foreach (Action a in actions)
            a();
    }
}

Obviously, the generated class behind the lambda is storing a reference or pointer to the int i variable, and is assigning a new value to the same reference every time the loop iterates. Is there a way to force the lamda to grab a copy instead, like the C++0x syntax

[&](){ ... } // Capture by reference

vs.

[=](){ ... } // Capture copies
Edit
Report

1 Answer

7

Remember that lambda expressions are really only syntactic sugar for anonymous methods.

That being said, what you are really looking for is how anonymous methods use local variables in a parent scope.

Here's a link describing this: Inside C# 2.0 Anonymous Methods

The article specifically goes into the pitfall of using this with loops, stating that this code:


public class Program
{
    public delegate void MyDelegate();
    public static void Main(string[] args)
    {
        MyDelegate d = null;
        for (int i = 1; i <= 5; i++)
        {
            MyDelegate tempD = delegate
            {
                Console.WriteLine(i);
            };
            d += tempD;
        }
        d();
    }
}

will surprisingly but predictably print "6 6 6 6 6".

This is explained:

any local variable captured within the anonymous method would be replaced by an instance data member of a newly created inner class for that scope

So the loop will create five instances of MyDelegate which all hold a reference to the loop-counter, which will have been incremented to 6 by the time the loop finishes. You cannot 'copy' a local variable with the lambda, but you can make sure that you only capture variables which won't be modified. Copying the variable i within the loop to a variable called copy like @Eclipse upvoted answer works, because copy is scoped to a single iteration. So while every delegate will capture copy by reference, they will all capture a different variable which is never modified!

answered 2009-01-16T20:20:51.847

Your Answer