代码之家  ›  专栏  ›  技术社区  ›  paradisonoir

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

  •  2
  • paradisonoir  · 技术社区  · 15 年前

    我不知道为什么我有一个 IndexOutOfRangeException 当我清理 System.Collections.Generic.List<T> . 这有道理吗?

    List<MyObject> listOfMyObject = new List<MyObject>();
    listOfMyObject.Clear(); 
    
    3 回复  |  直到 15 年前
        1
  •  18
  •   Reed Copsey    15 年前

    如果多个线程同时访问列表,则通常会发生这种情况。如果一个线程删除一个元素,而另一个线程调用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
    }
    
        2
  •  7
  •   jason    15 年前

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

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

    我也不例外。

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

    List<T>.Clear 很简单。使用反射镜:

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

    如果列表已经为空,则不会引发异常。但是,如果您正在修改另一个线程上的列表, Array.Clear 可以扔一个 IndexOutOfRangeException 例外。所以如果另一个线程从列表中删除了一个项,那么 this._size (要清除的项目数)太大。

        3
  •  1
  •   Kobi    15 年前

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