using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
MyClass myClass = new MyClass();
myClass.StartTasks();
}
}
class MyClass
{
int[] arr;
public void StartTasks()
{
arr = new int[2];
arr[0] = 100;
arr[1] = 101;
for (int i = 0; i < 2; i++)
{
Task.Factory.StartNew(() => WorkerMethod(arr[i])); // IndexOutOfRangeException: i==2!!!
}
}
void WorkerMethod(int i)
{
}
}
}
It seems that i++ gets executed one more time before the loop iteration is finished. Why do I get the IndexOutOfRangeException?
You are closing over loop variable. When it’s time for
WorkerMethodto get called,ican have the value of two, not the value of 0 or 1.When you use closures it’s important to understand that you are not using the value that the variable has at the moment, you use the variable itself. So if you create lambdas in loop like so:
and later execute the actions, they all will print “2”, because that’s what the value of
iis at the moment.Introducing a local variable inside the loop will solve your problem:
<Resharper plug> That’s one more reason to try Resharper – it gives a lot of warnings that help you catch the bugs like this one early. “Closing over a loop variable” is amongst them </Resharper plug>