清除List <T>时出现问题

par*_*oir 2 c# data-structures

我不知道为什么IndexOutOfRangeException我要清理时间System.Collections.Generic.List<T>.这有意义吗?

List<MyObject> listOfMyObject = new List<MyObject>();
listOfMyObject.Clear(); 
Run Code Online (Sandbox Code Playgroud)

Ree*_*sey 19

如果多个线程同时访问列表,通常会发生这种情况.如果一个线程删除一个元素而另一个线程调用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
}
Run Code Online (Sandbox Code Playgroud)


jas*_*son 7

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

using System.Collections.Generic;

class MyObject { }

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

而且我没有例外.

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

List<T>.Clear真的很简单.使用反射器:

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

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