ArgumentOutOfRangeException。但它不应该存在

时间:2013-12-07 08:30:29

标签: c# ajax asp.net-mvc

所以我有这样的方法。

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;

这种情况是当它进入第一个for循环并且两个集合中的元素数量假设为1时抛出ArgumentOutOfRangeException然后在Task.WaitAll()上抛出AggregateException,因为{{1}变成1(我不知道为什么,但确实如此)当它试图访问仅包含一个元素的数组中的第i个(第二个)元素时,就会发生这种情况。但还有更多。如果我在第一个循环之前设置一个断点并逐步进行,那么这个事情就不会发生。当i成为一个时,循环结束。一切都没问题。现在我上面提供的方法是由ASP.NET MVC Controller的Action调用的,它本身被称为Asynchronously(通过ajax调用)假设3次。在这三个中只有一个正确执行其他两个做我上面说过的事情(如果没有断点)。我认为这个问题是由ajax调用引起的,因为当我断点时它会阻止其他调用执行。谁能提出任何建议?

1 个答案:

答案 0 :(得分:4)

怀疑您在第一个循环中使用i,使用lambda表达式或匿名方法捕获它,如下所示:

for (int i = 0; i < taskCollection.Length; i++)
{
    taskCollection[i] = Task.Run(() => Console.WriteLine(i));
}

如果是这种情况,那就是正在捕获的变量 i - 而不是循环迭代的变量值。因此,当任务实际执行时,i的值可能已发生变化。解决方案是在循环中,在单独的“new”变量中获取迭代变量的副本,并在匿名函数中捕获它:

for (int i = 0; i < taskCollection.Length; i++)
{
    int copy = i;
    taskCollection[i] = Task.Run(() => Console.WriteLine(copy));
}

这样,每个任务都会捕获一个单独的变量,其值永远不会改变。