我有一个使用以下方法的课程:
public List<Bike> bikesCopy
{
get
{
List<Bike> bs;
lock (_bikes) bs = new List<Bike>(_bikes);
return bs;
}
}
其中包含另一个列表private List<Bike> _bikes;
现在奇怪的是,我收到以下错误:
目标数组不够长。检查destIndex和length,以及数组的下限。
这里有什么问题?
答案 0 :(得分:76)
我会说错误在于 _bikes 对象不是线程安全的。如评论所述,在某处可以修改未被锁定的 _bikes 对象。
这是一个瞬间错误,当测量 _bikes 的大小时,变量 bs 设置为X大小。在即将填充列表的下一个瞬间, _bikes 对象的大小增加,从而产生错误。
请仔细阅读您的代码。查找 _bikes 对象的所有引用,并确保它们是线程安全处理(带锁定)。
答案 1 :(得分:7)
你可以试试:
using System.Linq; //ToList() is an extension function defined here
...
lock(_bikes)
return _bikes.ToList();
此处讨论了例外的详细信息:Why doesn't a foreach loop work in certain cases?
答案 2 :(得分:1)
发生此错误是因为多个线程正在单个列表中添加项目。默认情况下,列表不是线程安全的解决方案。在多线程代码中,仅建议从列表中读取而不是写入列表。
如here所述:
如果您仅从共享馆藏中阅读,则可以使用 System.Collections.Generic命名空间中的类。
最好使用诸如System.Collections.Concurrent命名空间之类的线程安全解决方案,该解决方案提供诸如ConcurrentBag,ConcurrentDictionary,ConcurrentQueue,ConcurrentStack等实现。
例如:
public ConcurrentBag<Bike> bikesCopy
{
get => new ConcurrentBag<Bike>()
}
答案 3 :(得分:0)
不是真正的答案,更多是研究评论。
我遇到了同样的问题并进行了快速测试。
我尝试使用下面的代码,无法使用此代码抛出ArgumentException: Destination array was not long enough
。但是当我从行
.ToList()
时
return allLines.ToList().ToArray();
它会立即崩溃。
这是演示代码,即使IDE告诉我,我应该删除ToList()
调用,因为它似乎是多余的。
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);
}
}
}
我真的很想知道,为什么它不会崩溃,因为List也有一个数组支持。