我在通过队列枚举时遇到以下异常:
System.InvalidOperationException: 收集被修改;列举 操作可能无法执行
这是代码摘录:
1: private bool extractWriteActions(out List<WriteChannel> channelWrites)
2: {
3: channelWrites = new List<WriteChannel>();
4: foreach (TpotAction action in tpotActionQueue)
5: {
6: if (action is WriteChannel)
7: {
8: channelWrites.Add((WriteChannel)action);
9: lock(tpotActionQueue)
10: {
11: action.Status = RecordStatus.Batched;
12: }
13: }
14: }
15: return (channelWrites.Count > 0);
16: }
我想我理解了这个问题 - 改变了action.Status = RecordStatus.Batched
的哈希表,这搞砸了枚举器上的MoveNext()。
问题是,我该如何正确实现“模式”?
答案 0 :(得分:8)
我认为在Collection上使用foreach
循环时遇到了类似的异常,我试图从Collection中删除项目(或者它可能是List,我不记得了)。我最后使用for
循环绕过它。也许尝试以下内容:
for (int i=0; i<tpotActionQueue.Count(); i++)
{
TpotAction action = tpotActionQueue.Dequeue();
if (action is WriteChannel)
{
channelWrites.Add((WriteChannel)action);
lock(tpotActionQueue)
{
action.Status = RecordStatus.Batched;
}
}
}
答案 1 :(得分:6)
您可以更改集合中项目的值。你得到的错误意味着一个项目被添加或删除,即:集合本身被修改,而不是集合中的项目。这很可能是由另一个线程在此集合中添加或删除项目引起的。
您应该在方法的开头锁定队列,以防止其他线程在您访问它时修改集合。或者你可以在调用这个方法之前锁定集合。
private bool extractWriteActions(out List<WriteChannel> channelWrites)
{
lock(tpotActionQueue)
{
channelWrites = new List<WriteChannel>();
foreach (TpotAction action in tpotActionQueue)
{
if (action is WriteChannel)
{
channelWrites.Add((WriteChannel)action);
action.Status = RecordStatus.Batched;
}
}
}
return (channelWrites.Count > 0);
}
答案 2 :(得分:1)
您没有tpotActionQueue
的定义,但如果它只是正常的List<TpotAction>
,则该行不是您的问题。修改集合是添加或删除成员 - 不在包含的对象上设置属性。
你有一个lock(tpotActionQueue)
和一个线程安全标记,所以我猜是在你枚举时还有另一个线程在tpotActionQueue
添加或删除项目。您可能需要同步这些访问。
答案 3 :(得分:0)
我认为您需要做的就是停止使用foreach,而是将其切换为for循环
for(int i = 0; i < tpotActionQueue.Length; i++)
{
TpotAction action = tpotActionQueue[i];
if (action is WriteChannel)
{
channelWrites.Add((WriteChannel)action);
lock(tpotActionQueue)
{
action.Status = RecordStatus.Batched;
}
}
}
问候,迈克。
答案 4 :(得分:0)
一些LINQy善良怎么样?
private bool extractWriteActions(out List<WriteChannel> channelWrites)
{
channelWrites= tpotActionQueue.Where<WriteChannel>(x => x is WriteChannel).ToList()
foreach(WriteChannel channel in channelWrites) {
channel.Status = RecordStatus.Batched;
}
return ( channelWrites.Count > 0);
}
答案 5 :(得分:-1)
我认为你在迭代时必须修改tpotActionQueue。由于您只是在for循环中锁定该队列,因此这是可能的。