也许有人可以指出我正确的方向,因为我完全被这个困扰了。
我有一个只打印出类的LinkedList的函数:
LinkedList<Component> components = new LinkedList<Component>();
...
private void PrintComponentList()
{
Console.WriteLine("---Component List: " + components.Count + " entries---");
foreach (Component c in components)
{
Console.WriteLine(c);
}
Console.WriteLine("------");
}
Component
对象实际上有一个自定义ToString()
调用:
int Id;
...
public override String ToString()
{
return GetType() + ": " + Id;
}
这个函数通常运行正常 - 但是我遇到的问题是,当它在列表中构建大约30个条目时,PrintcomplentList
foreach
语句返回{{1 }}
现在您可以看到我没有修改for循环中的代码,并且我没有显式创建任何线程,尽管这是在XNA环境中(如果它很重要)。应该注意的是,打印输出频繁,控制台输出整体上减慢了程序的速度。
我完全难过了,还有其他人遇到过这个吗?
答案 0 :(得分:11)
我怀疑开始寻找的地方会在你操纵列表的任何地方 - 即插入/移除/重新分配项目。我怀疑是会有一个回调/偶数处理程序,它会被异步触发(可能作为XNA paint 等循环的一部分),并且正在编辑列表 - 实际上导致此问题竞争条件。
要检查是否是这种情况,请在操作列表的位置周围放置一些调试/跟踪输出,并查看它是否曾经(特别是在异常之前)与您的同时运行操作代码控制台输出:
private void SomeCallback()
{
Console.WriteLine("---Adding foo"); // temp investigation code; remove
components.AddLast(foo);
Console.WriteLine("---Added foo"); // temp investigation code; remove
}
不幸的是,这些事情通常很难调试,因为更改代码来调查它通常会改变问题(Heisenbug)。
一个答案是同步访问;即在所有编辑列表的地方,在整个操作周围使用lock
:
LinkedList<Component> components = new LinkedList<Component>();
readonly object syncLock = new object();
...
private void PrintComponentList()
{
lock(syncLock)
{ // take lock before first use (.Count), covering the foreach
Console.WriteLine("---Component List: " + components.Count
+ " entries---");
foreach (Component c in components)
{
Console.WriteLine(c);
}
Console.WriteLine("------");
} // release lock
}
和你的回调(或其他)
private void SomeCallback()
{
lock(syncLock)
{
components.AddLast(foo);
}
}
特别是,“完整操作”可能包括:
foreach
/ for
(即不是个人/离散的操作 - 而是工作单位)
答案 1 :(得分:5)
我使用foreach
而不是while( collection.count >0)
,而是使用collection[i]
。
答案 2 :(得分:2)
我不知道这是否与OP有关但我有同样的错误,并在谷歌搜索期间找到了这个帖子。我能够通过在删除循环中的元素后添加一个中断来解决它。
foreach( Weapon activeWeapon in activeWeapons ){
if (activeWeapon.position.Z < activeWeapon.range)
{
activeWeapons.Remove(activeWeapon);
break; // Fixes error
}
else
{
activeWeapon.position += activeWeapon.velocity;
}
}
}
如果省略休息,您将收到错误“InvalidOperationException:在实例化枚举数后修改了集合。”
答案 3 :(得分:0)
使用Break
可能是一种方式,但它可能会影响您的一系列操作。
在这种情况下我只需将foreach
转换为传统的for
循环
for(i=0; i < List.count; i++)
{
List.Remove();
i--;
}
这没有任何问题。