在什么情况下System.Collections.ArrayList.Add会抛出IndexOutOfRangeException?

时间:2010-09-25 14:20:04

标签: .net collections arraylist

我们在生产环境中遇到奇怪的错误,我们无法调试或注入日志代码。我试图解决这个问题,但是跟踪堆栈跟踪让我很困惑。

System.IndexOutOfRangeException: Index was outside the bounds of the array.
   at System.Collections.ArrayList.Add(Object value)
   at ...

According to the MSDN Add方法只应抛出NotSupportedException

我不知道这里发生了什么。你呢?

3 个答案:

答案 0 :(得分:19)

当“尝试访问索引超出数组边界的数组元素时,抛出IndexOutOfRangeException。”

请注意ArrayList类不是线程安全的。在多线程场景中,竞争条件可能会导致ArrayList尝试在超出其范围的索引处读取/写入后备阵列。

示例:一个线程在另一个线程添加到集合的同时减小了后备阵列的大小(可能通过TrimToSize调用)。现在,如果支持阵列处于满容量状态,则添加线程将尝试扩展其容量(通过分配新阵列)以容纳新元素。同时TrimToSize调用会反转此效果。然后,当添加线程尝试写入数组时,它思想的索引将不再可用,从而导致抛出异常。

修复:根据您的情况使用线程安全结构。

答案 1 :(得分:11)

这几乎肯定是并发问题......您可能有两个线程同时修改集合,ArrayList类不支持并发访问。出现竞争条件,有时会导致其中一个线程尝试在数组边界之外的位置写入。

尝试使用lock语句保护对集合的所有访问,或使用集合的同步包装(使用ArrayList.Synchronized方法)

答案 2 :(得分:10)

归结为List不是线程安全的。我在使用多个线程添加项目之后迭代列表时发生了IndexOutOfRangeException,如下所示

List<TradeFillInfo> updatedFills = new List<TradeFillInfo>();
Parallel.ForEach (trades, (trade) =>
{
    TradeFillInfo fill = new TradeFillInfo();

    //do something

    updatedFills.Add(fill); //NOTE:Adding items without synchronization
});

foreach (var fill in updatedFills) //IndexOutOfRangeException here sometimes
{
    //do something
}

在这种情况下,updatedFills计数被破坏,后续迭代失败。围绕lock语句包含Add()应该可以防止这种情况。

lock (updatedFills)
{
    updatedFills.Add(fill);
}