Can ToArray() throw an exception? Can ToArray() throw an exception? multithreading multithreading

Can ToArray() throw an exception?


You will not find documentation about possible exceptions of ToArray method for one simple reason. This is an extension method that has many 'overloads'. They all have same method signature, but implementation is different for different collection types, e.g. List<T> and HashSet<T>.

However, we can make a safe assumption for most of the code that .NET framework BCL does not perform any locking for performance reasons. I've also checked very specifically implementation of ToList for List<T>.

public T[] ToArray(){    T[] array = new T[this._size];    Array.Copy(this._items, 0, array, 0, this._size);    return array;}

As you might have imagined, it's quite simple code which ends up executing in mscorlib.For this specific implementation, you can also see exceptions which could occur in MSDN page for Array.Copy method. It boils down to an exception which is thrown if rank of the list changes right after destination array was just allocated.

Having in mind that List<T> is trivial example, you can imagine that chances for exception rise on structures which require more complicated code in order to store in an array. Implementation for Queue<T> is a candidate which is more likely to fail:

public T[] ToArray(){    T[] array = new T[this._size];    if (this._size == 0)    {        return array;    }    if (this._head < this._tail)    {        Array.Copy(this._array, this._head, array, 0, this._size);    }    else    {        Array.Copy(this._array, this._head, array, 0, this._array.Length - this._head);        Array.Copy(this._array, 0, array, this._array.Length - this._head, this._tail);    }    return array;}


When thread-safety is not explicitly guaranteed by the docs or by principle you cannot assume it. If you do assume it you risk putting a class of bugs into production that is undebuggable and has the potential to cost you a lot of productivity/availability/money. Are you willing to take that risk?

You can never test something to be threadsafe. You can never be sure. You cannot be sure that a future version behaves the same way.

Do it the right way and lock.

Btw, these remarks were for List.ToArray which is one of the more safe versions of ToArray. I understand why one would mistakenly think it can be used concurrently with writes to the list. Of course IEnumerable.ToArray cannot possibly be threadssafe because that is a property of the underlying sequence.


ToArray is NOT threadsafe, and this code proves it!

Consider this rather ridiculous code:

        List<int> l = new List<int>();        for (int i = 1; i < 100; i++)        {            l.Add(i);            l.Add(i * 2);            l.Add(i * i);        }        Thread th = new Thread(new ThreadStart(() =>        {            int t=0;            while (true)            {                //Thread.Sleep(200);                switch (t)                {                    case 0:                        l.Add(t);                        t = 1;                        break;                    case 1:                        l.RemoveAt(t);                        t = 0;                        break;                }            }        }));        th.Start();        try        {            while (true)            {                Array ai = l.ToArray();                //foreach (object o in ai)                //{                //    String str = o.ToString();                //}            }        }        catch (System.Exception ex)        {            String str = ex.ToString();                         }    }

This code will fail in a very short run, because of the l.Add(t) line. Because the ToArray is NOT threadsafe, it will allocate the array to the current size of l, then we will add an element to l (in the other thread), and then it will try to copy the current size of l to ai and fail because l has too many elements. ToArray throws an ArgumentException.