简体   繁体   中英

Problem with clearing a List<T>

I don't know why I have an IndexOutOfRangeException when I am clearing a System.Collections.Generic.List<T> . Does this make sense?

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

This typically happens if multiple threads are accessing the list simultaneously. If one thread deletes an element while another calls Clear(), this exception can occur.

The "answer" in this case is to synchronize this appropriately, locking around all of your List access.


Edit:

In order to handle this, the simplest method is to encapsulate your list within a custom class, and expose the methods you need, but lock as needed. You'll need to add locking to anything that alters the collection.

This would be a simple option:

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
}

Are you sure that that code throws an exception? I have

using System.Collections.Generic;

class MyObject { }

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

and I do not get an exception.

Is your real-life example more complex? Perhaps you have multiple threads simultaneously accessing the list? Can we see a stack trace?

List<T>.Clear is really quite simple. Using Reflector:

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

In the case when the list already empty, that is not going to ever throw an exception. However, if you are modifying the list on another thread, Array.Clear could throw an IndexOutOfRangeException exception. So if another thread removes an item from the list then this._size (the number of items to clear) will be too big.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM