paradisonoir
paradisonoir

Reputation: 2910

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(); 

Upvotes: 2

Views: 3876

Answers (3)

Reed Copsey
Reed Copsey

Reputation: 564373

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
}

Upvotes: 19

jason
jason

Reputation: 241601

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.

Upvotes: 7

Kobi
Kobi

Reputation: 138007

The documentation doesn't mention any Exception this method throws, your problem is probably elsewhere.
List<T>.Clear

Upvotes: 1

Related Questions