4

I am tearing my hair off because of the following issue. I have this bit of code that loops through a list of objects and creates a processing task for each of them.

        IList<TileInfo> tiles = tileSource.Schema.GetTilesInView(extent, level);
        List<Task> renderingTasks = new List<Task>();
        foreach (TileInfo info in tiles) {
            renderingTasks.Add(Task.Factory.StartNew(new Action(delegate {
                Console.WriteLine(Task.CurrentId +"Info object"+ info.GetHashCode());
                             }
                         })));
        }

This code prints:

1Info object36963566
2Info object36963566
3Info object36963566
4Info object36963566
5Info object36963566
6Info object36963566
7Info object36963566
8Info object36963566
9Info object36963566
10Info object36963566
11Info object36963566
12Info object36963566
...

As you can see, the problem is that the tasks seem to all have a reference to one object!

Why are the tasks all using only one object from the list?

Thanks for you help

0

2 Answers 2

5

I'll try and add some more detail in a moment, but it's about closing over the variable. Change you code to:

Essentially what you need to do, is create a new variable inside the loop, equal to the single declaration outside the inner workings of the loop.

IList<TileInfo> tiles = tileSource.Schema.GetTilesInView(extent, level);
List<Task> renderingTasks = new List<Task>();

foreach (TileInfo info in tiles) 
{
   TileInfo closingInfo = info;
   renderingTasks.Add(Task.Factory.StartNew(new Action(delegate {
                      Console.WriteLine(Task.CurrentId +"Info object"+ closingInfo.GetHashCode()); }})));
}

To Read more:

The foreach identifier and closures

http://blogs.msdn.com/b/ericlippert/archive/2009/11/12/closing-over-the-loop-variable-considered-harmful.aspx

Sign up to request clarification or add additional context in comments.

Comments

4

object36963566 must be last instance in your tiles list

This is because how the foreach works in current implementation of .Net. Although it will be fixed in future.

You need to read Closing over the loop variable considered harmful for understanding how foreach works in this case.

Task.CurrentId +"Info object"+ info.GetHashCode()

info in above code is referring to an item in the list tiles. The delegate you are creating will not use the item info was referring to when it(delegate) was created. Rather it will use the current value of info(value that info was pointing to when the method/delegate will actually run) which is obviously pointing to last item of the list. That's why you are getting this behaviour

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.