System.InvalidOperationException:集合已被修改

我在通过队列枚举时遇到以下exception:

System.InvalidOperationException:集合已被修改; 枚举操作可能无法执行

这是代码摘录:

1: private bool extractWriteActions(out List channelWrites) 2: { 3: channelWrites = new List(); 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的哈希表,它action.Status = RecordStatus.Batched了枚举器上的MoveNext()。 问题是,我该如何正确实现“模式”?

您可以更改集合中项目的值。 您获得的错误意味着添加或删除了一个项目,即:集合本身已被修改,而不是集合中的项目。 这很可能是由另一个线程向此集合添加或删除项目引起的。

您应该在方法的开头锁定队列,以防止其他线程在您访问它时修改集合。 或者您可以在调用此方法之前锁定集合。

 private bool extractWriteActions(out List channelWrites) { lock(tpotActionQueue) { channelWrites = new List(); foreach (TpotAction action in tpotActionQueue) { if (action is WriteChannel) { channelWrites.Add((WriteChannel)action); action.Status = RecordStatus.Batched; } } } return (channelWrites.Count > 0); } 

我认为我在Collection上使用foreach循环时遇到类似的exception,我试图从Collection中删除项目(或者它可能是List,我不记得了)。 我最后通过使用for循环来绕过它。 也许尝试以下内容:

 for (int i=0; i 

你没有tpotActionQueue的定义,但是如果它只是一个普通的List那么那条线不是你的问题。 修改集合是添加或删除成员 – 不在包含的对象上设置属性。

你有一个lock(tpotActionQueue)和一个线程安全的标签,所以我猜你在枚举时还有另一个线程在tpotActionQueue添加或删除项目。 您可能需要同步这些访问。

我认为您需要做的就是停止使用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; } } } 

问候,迈克。

一些LINQy善良怎么样?

 private bool extractWriteActions(out List channelWrites) { channelWrites= tpotActionQueue.Where(x => x is WriteChannel).ToList() foreach(WriteChannel channel in channelWrites) { channel.Status = RecordStatus.Batched; } return ( channelWrites.Count > 0); } 

我想你必须有一些其他线程修改tpotActionQueue,而你在迭代它。 由于您只是在for循环中锁定该队列,因此这是可能的。