C# Code, Tutorials and Full Visual Studio Projects

Access to Modified Closure

Posted by on Nov 16, 2010 in Bugs | 3 comments

Access to Modified Closure

If you use Resharper like me you probably see “Access to modified closure” once in awhile and have learned to ignore it, after all it never seems to be a problem right?

Well yeah as you can guess my code went pop the other day because of it and so I thought I would share what happened.

I had a list of objects and I wanted to enumerate through them and spawn separate threads to do background work on each one.  Once I ran the code I noticed a problem a runtime, it looked like all my background workers were using the same object instead of different ones!

Here is a simplified c# example of the problem:

private static void Main(string[] args)
{
    List<string> values = new List<string>();

    for (int i = 0; i <= 1000; i++)
    {
        values.Add(i.ToString());
    }

    foreach (string value in values)
    {
        Task.Factory.StartNew(() => PrintLn(value));
    }

    Console.ReadLine();
}

public static void PrintLn(string input)
{
    Console.WriteLine(input);
}

So you can see that this code should print 1 to 1000 out on the command line right?

Well it doesn’t the output is 1000 printed 1000 times.

Score one for Resharper. It was right, my code was busted.  the problem stems from that PrintLn(value) statement in the Task call.  Since were enumerating value, it’s value is changing as since were passing a reference to our function to be executed sometime later, by the time that function PrintLn gets around to executing the enumeration has completed and the value of the variable value is 1000.

You can fix this easily enough by doing something like this:

foreach (string value in values)
{
    string tmpValue = value;
    Task.Factory.StartNew(() => PrintLn(tmpValue));
}

Looks a bit strange but does get the job done.

Just wanted to put this out there because I’m sure others have ran into the same issue.

Code safe. (and listen to Resharper!)

3 Comments

Join the conversation and post a comment.

  1. Vk

    Strange, just few days ago had the same kind of issue. Thanks to Resharper!

  2. mklemm

    I think you should also briefly explain why the strange looking tmpValue assignment works.
    It is because inside the loop a new local variable is declared, i.e. allocated, on every iteration. What then gets passed into the lambda expression is a different variable on every iteration, not just the single one loop variable. So, don’t be fooled and try

    string tmpValue = null;
    foreach (string value in values)
    {
    tmpValue = value;
    Task.Factory.StartNew(() => PrintLn(tmpValue));
    }

    which would exhibit the same behaviour as just using the loop variable…

  3. kelias

    Thanks mklemm, great description!

Leave a Comment

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>