Have you noticed that Resharper will occasionally give you a warning with the message “Access to modified closure” when referencing a variable within an anonymous method or lambda expression? Take the following code snippet for example:
class Program
{static void Main(string[] args){List<Action> actions = new List<Action>();
for (int i = 1; i <= 10; i++)actions.Add(() => Console.WriteLine(i));foreach (var action in actions)action();}}Note that we could also write this example in .Net 2.0 using anonymous methods:
class Program
{private delegate void Action();static void Main(string[] args){List<Action> actions = new List<Action>();
for (int i = 1; i <= 10; i++)actions.Add(delegate() { Console.WriteLine(i); });
foreach (var action in actions)action();}}At first glance, it looks like the output of this example should count from 1 to 10. Instead, we see this:
The use of the variable i in the delegate makes use of a language feature called Closure. In this case, the newly created delegate is a closure that is dependant upon the variable i. Through closures, the delegates are tied to the variable i (outside of the delegate) instead of the value that’s in i when the delegate is created. The value of i is incremented via the for loop, so when we actually invoke the collection of delegates, they all print the same value since they are all bound to the same instance of i (which sounds really weird since i is actually a value type, but I believe .Net is actually creating a reference object to represent the variable i within the delegate).
So how do we get around this? The solution is actually pretty easy. Create a local variable in the for loop that is instantiated in each iteration with the current value of i.
class Program
{static void Main(string[] args){List<Action> actions = new List<Action>();
for (int i = 1; i <= 10; i++){int j = i;
actions.Add(() => Console.WriteLine(j));}foreach (var action in actions)action();}}Note that we’re now using the new local variable j within the delegate. Since it’s created within the loop, each delegate will be referencing to their own j variable.
While the concept of closures was new to me, there are a lot of really good blog articles out there on the subject. Check out the following for more reading:
- Fibonacci Numbers, Caching and Closures
- Closures and Continuations
- Lambdas and Closures and Currying. Oh my! (Part 1) – Justin has an awesome series on the functional aspects of C#.
Really helpful 🙂
I was doing something like:
foreach (var s in ____)
{
m = delegate
{
checkedListBox.Items.Add(s.Name, false);
};
}
and it was showing the Name field of the last s in ________ 😉
whoah this weblog is fantastic i really like studying your articles.
Stay up the good work! You realize, a lot of people are searching around for
this information, you can aid them greatly.
Very good post. I’m going through a few of these issues as well..