71

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?

Jeroen Vannevel
44.5k25 gold badges113 silver badges174 bronze badges
asked Apr 28, 2012 at 8:50
4
  • Where exactly do you get the exception? Can you update the question with the exception stack trace and point out the exact code line where it is thrown? Commented Apr 28, 2012 at 8:57
  • Yes, it is the following message (sorry for the mess): at System.Array.Copy(Array sourceArray, Int32 sourceIndex, Array destinationArray, Int32 destinationIndex, Int32 length, Boolean reliable) at System.Array.Copy(Array sourceArray, Int32 sourceIndex, Array destinationArray, Int32 destinationIndex, Int32 length) at System.Collections.Generic.List'1.CopyTo(T[] array, Int32 arrayIndex) at System.Collections.Generic.List'1..ctor(IEnumerable'1 collection) at MyGame.Player.get_bikesCopy() Commented Apr 28, 2012 at 12:49
  • 2
    Did you every get to the root cause of this problem? I am running into something similar. Commented Oct 9, 2012 at 21:03
  • 7
    If you didn't resolve this, I believe the problem could be that you have not put a lock around the bikes.Add() method (or maybe another List method). This is because the Add method is not thread safe in a List. Anyway, hope that helps if anyone gets the same problem Commented Oct 22, 2012 at 11:18

4 Answers 4

130

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).

answered Jan 2, 2013 at 8:23

4 Comments

I am terribly sorry, I accidentally clicked on downvote but I actually wanted to upvote and now I cannot un-vote anymore :-/ Sorry!!
That is ok. The worst is when you get down voted and have no clue to as of why.
Yeah, I got a "fan" a couple of days ago (18 downvotes within 2 minutes) and learned about the anti-serial-downvoting bot. I really like that bot :-) P.S.: The website says, if you edit the answer, I can undo the downvote again.
What did you edit?! I am confused... However: I like bikes :-)
8

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>()
}
answered May 6, 2020 at 5:01

Comments

6

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: Why doesn't a foreach loop work in certain cases?

answered Apr 28, 2012 at 8:59

4 Comments

I am not capable using LINQ, as it is not whitelisted on my framework.... Anyway, it doesn't answer my problem either :)
You can't use LINQ?!?!? I'd quit that job as soon as I found that out!
Not sure why, but .ToList() works great versus new List<T>(YourList), which always throws an exception.
@JamesM It's the line _items = new T[capacity]; in the source code for List<T> (referencesource.microsoft.com/mscorlib/system/collections/…) which makes all the difference.
0

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.

answered Feb 12, 2018 at 15:42

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.