清除列表<t> </t>时出现问题

时间:2009-09-15 20:55:14

标签: c# data-structures

当我清除IndexOutOfRangeException时,我不知道为什么我有System.Collections.Generic.List<T>。这有意义吗?

List<MyObject> listOfMyObject = new List<MyObject>();
listOfMyObject.Clear(); 

3 个答案:

答案 0 :(得分:18)

如果多个线程同时访问列表,通常会发生这种情况。如果一个线程删除一个元素而另一个线程调用Clear(),则可能发生此异常。

在这种情况下,“答案”是适当地同步,锁定所有列表访问权限。


编辑:

为了处理这个问题,最简单的方法是将列表封装在自定义类中,并公开所需的方法,但需要锁定。您需要为改变集合的任何内容添加锁定。

这是一个简单的选择:

public class MyClassCollection
{
    // Private object for locking
    private readonly object syncObject = new object(); 

    private readonly List<MyObject> list = new List<MyObject>();
    public this[int index]
    {
        get { return list[index]; }
        set
        {
             lock(syncObject) { 
                 list[index] = value; 
             }
        }
    }

    public void Add(MyObject value)
    {
         lock(syncObject) {
             list.Add(value);
         }
    }

    public void Clear()
    {
         lock(syncObject) {
             list.Clear();
         }
    }
    // Do any other methods you need, such as remove, etc.
    // Also, you can make this class implement IList<MyObject> 
    // or IEnumerable<MyObject>, but make sure to lock each 
    // of the methods appropriately, in particular, any method
    // that can change the collection needs locking
}

答案 1 :(得分:7)

您确定该代码会引发异常吗?我有

using System.Collections.Generic;

class MyObject { }

class Program {
    static void Main(string[] args) {
        List<MyObject> listOfMyObject = new List<MyObject>();
        listOfMyObject.Clear();
    }
}

我没有例外。

你的现实生活中的例子更复杂吗?也许你有多个线程同时访问列表?我们能看到堆栈跟踪吗?

List<T>.Clear非常简单。使用Reflector:

public void Clear() {
    if (this._size > 0) {
        Array.Clear(this._items, 0, this._size);
        this._size = 0;
    }
    this._version++;
}

如果列表已经为空,那就不会抛出异常。但是,如果要修改另一个线程上的列表,Array.Clear可能会抛出IndexOutOfRangeException异常。因此,如果另一个线程从列表中删除了一个项目,那么this._size(要清除的项目数量)将会太大。

答案 2 :(得分:1)

文档没有提到此方法抛出的任何异常,您的问题可能在其他地方 List<T>.Clear