Destination Array not long enough?

C#ListLocking

C# Problem Overview


I have a class with the following method:

public List<Bike> bikesCopy 
{
     get 
     { 
       List<Bike> bs;
       lock (_bikes) bs = new List<Bike>(_bikes);
       return bs;
     }
}

Which makes a copy of another list, private List<Bike> _bikes;

The strange thing now is, that I get the following error:

> Destination array was not long enough. Check destIndex and length, and the array's lower bounds.

What is the problem here?

C# Solutions


Solution 1 - C#

I would say the error lies in the object _bikes not being thread safe. As commented, somewhere there is a modify of the _bikes object that is not being lock'ed.

It is a split second error where the variable bs is set up to a size X when the size of _bikes is measured. In the next split second as it is about to fill the list, the _bikes object has increased in size giving the error.

So go over your code. Find all references of your _bikes object and make sure they are thread safe handled (with lock).

Solution 2 - C#

Well you could try:

using System.Linq; //ToList() is an extension function defined here
...
lock(_bikes)
    return _bikes.ToList();

The details of the exception are discussed here: https://stackoverflow.com/questions/1167333/why-doesnt-a-foreach-loop-work-in-certain-cases

Solution 3 - C#

This error occurs because multiple threads are adding items in a single list. Lists are by default not a thread-safe solution. In a multi-threaded code, it is only recommended to read from a list, and not write to it.

As described here:

> If you are only reading from a shared collection, then you can use the > classes in the System.Collections.Generic namespace.

Better use a thread-safe solution like System.Collections.Concurrent namespace which provides implementations like ConcurrentBag, ConcurrentDictionary, ConcurrentQueue, ConcurrentStack etc.

For example:

public ConcurrentBag<Bike> bikesCopy 
{
     get => new ConcurrentBag<Bike>()
}

Solution 4 - C#

Not really an answer, more a research comment.

I ran into the same problem and did a quick test. I tried with the code below and could not get this code to throw the ArgumentException: Destination array was not long enough. But when I remove the .ToList() from the line

return allLines.ToList().ToArray();

it immediately crashes.

This is the demo code and even the IDE tells me, I should remove the ToList() call as it seems redundant.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;

namespace ConsoleApp1
{
    class Program
    {
        static void Main() {

            List<string> thelist = new List<string>();

            Thread producer = new Thread(() => {
                while (true) {
                    thelist.Add("a" + DateTime.Now);
                }
            });

            Thread transformer = new Thread(() => {
                while (true) {
                    string[] thearray = thelist.ToList().ToArray();
                    Console.WriteLine(thearray.Length);
                }
            });
            producer.Start();
            transformer.Start();
            Console.ReadKey(true);
        }
    }
}

I really wonder, why it would not crash, as the List is also backed by an array.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionGeertView Question on Stackoverflow
Solution 1 - C#Wolf5View Answer on Stackoverflow
Solution 2 - C#edvaldigView Answer on Stackoverflow
Solution 3 - C#Kush GroverView Answer on Stackoverflow
Solution 4 - C#Xan-Kun Clark-DavisView Answer on Stackoverflow