C# System.InvalidOperationException:集合已修改
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1154350/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
System.InvalidOperationException: Collection was modified
提问by kermit_xc
I am getting a following exception while enumerating through a queue:
我在枚举队列时遇到以下异常:
System.InvalidOperationException: Collection was modified; enumeration operation may not execute
System.InvalidOperationException:集合已修改;枚举操作可能不会执行
here is the code excerpt:
这是代码摘录:
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: }
I think I understand the problem - altering the hashtable at action.Status = RecordStatus.Batched
, which screws up the MoveNext() on enumerator.
Question is, how do I implement that "pattern" correctly?
我想我明白这个问题 - 在 更改哈希表action.Status = RecordStatus.Batched
,这搞砸了枚举器上的 MoveNext()。问题是,我如何正确实施该“模式”?
采纳答案by Stan R.
You are allowed to change the value in an item in a collection. The error you're getting means that an item was either added or removed i.e.: the collection itself was modified, not an item inside the collection. This is most likely caused by another thread adding or removing items to this collection.
您可以更改集合中项目的值。您收到的错误意味着添加或删除了一个项目,即:修改了集合本身,而不是集合内的项目。这很可能是由另一个线程向该集合添加或删除项目引起的。
You should lock your queue at the beginning of your method, to prevent other Threads modifying the collection while you are accessing it. Or you could lock the collection before even calling this method.
你应该在你的方法开始时锁定你的队列,以防止其他线程在你访问它时修改它。或者您甚至可以在调用此方法之前锁定集合。
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);
}
回答by Michael Ciba
I think all you need to do is stop using the foreach and instead switch it over to a for loop
我认为您需要做的就是停止使用 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;
}
}
}
Regards, Mike.
问候,迈克。
回答by CodeGoat
I think you must have some other thread modifying the tpotActionQueue while you're iterating over it. Since you're only locking that queue inside the for loop this is possible.
我认为您在迭代它时必须有一些其他线程修改 tpotActionQueue 。由于您只是在 for 循环内锁定该队列,因此这是可能的。
回答by Sarah Vessels
I think I had a similar exception when using a foreach
loop on a Collection where I tried to remove items from the Collection (or it may have been a List, I can't remember). I ended up getting around it by using a for
loop. Perhaps try something like the following:
我想我foreach
在尝试从集合中删除项目的集合上使用循环时遇到了类似的异常(或者它可能是一个列表,我不记得了)。我最终通过使用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;
}
}
}
回答by Mark Brackett
You don't have a definition for tpotActionQueue
, but if it's just a normal List<TpotAction>
then that line is not your problem. Modifying the collection is adding or removing members - not setting a property on a contained object.
你没有 的定义tpotActionQueue
,但如果它只是一个正常的,List<TpotAction>
那么那条线不是你的问题。修改集合是添加或删除成员 - 不是在包含的对象上设置属性。
You have a lock(tpotActionQueue)
and a tag of thread-safety, so my guess is there's another thread adding or removing items from tpotActionQueue
while you're enumerating. You probably need to synchronize those accesses.
您有一个lock(tpotActionQueue)
和 线程安全标签,所以我猜测tpotActionQueue
在您枚举时还有另一个线程添加或删除项目。您可能需要同步这些访问。
回答by Kirschstein
How about some LINQy goodness?
来点 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);
}