So I have and method like this.
var someColletion = _someService.GetSomeCollection(someParam);
var taskCollection = new Task<double>[someCollection.Count];
for (int i = 0; i < taskCollection.Length; i++)
{
// do some stuff on the i-th element of someCollection and taskCollection
// and start the i-th task
}
Task.WaitAll(taskCollection);
double total = 0;
for (int i = 0; i < taskCollection.Length; i++)
{
// get the result of each task and sum it in total variable
}
return total;
the case is when it comes into first for loop and the number of elements in both collections are suppose 1 the ArgumentOutOfRangeException
is being thrown and then AggregateException is being thrown on Task.WaitAll()
because the i
becomes 1 (I don't know why but it does) and when it tries to access the i-th (second) element in array that contains just one element, this happens. But there is more to this. If i set a break point before first loop and go step by step then this thing does not happen. when i
becomes one the cycle ends. and everything's okay. now the method I provided above is called by an ASP.NET MVC Controller's Action which itself is called Asynchronously (by ajax call) suppose 3 times. and out of this three just one executes correctly other two do the thing I said above (if not breakpointed). I think that this problem is caused by ajax call most probably because when I breakpoint it stops other calls from executing. Can anyone suggest anything ?
I suspect you're using i
within the first loop, capturing it with a lambda expression or anonymous method, like this:
for (int i = 0; i < taskCollection.Length; i++)
{
taskCollection[i] = Task.Run(() => Console.WriteLine(i));
}
If that's the case, it's the variable i
which is being captured - not the value of the variable for that iteration of the loop. So by the time the task actually executes, it's likely that the value of i
has changed. The solution is to take a copy of the iteration variable within the loop, in a separate "new" variable, and capture that in the anonymous function instead:
for (int i = 0; i < taskCollection.Length; i++)
{
int copy = i;
taskCollection[i] = Task.Run(() => Console.WriteLine(copy));
}
That way, each task captures a separate variable, whose value never changes.
See more on this question at Stackoverflow