[英]Strange “Collection was modified after the enumerator was instantiated” exception
也許有人可以指出我正確的方向,因為我完全被這個困擾了。
我有一個函數,只是打印出一個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
語句返回InvalidOperationException: Collection was modified after the enumerator was instantiated.
現在您可以看到我沒有修改for循環中的代碼,並且我沒有顯式創建任何線程,盡管這是在XNA環境中(如果它很重要)。 應該注意的是,打印輸出頻繁,控制台輸出整體上減慢了程序的速度。
我完全難過了,有沒有其他人遇到這個?
我懷疑開始尋找的地方將在你操縱列表的任何地方 - 即插入/刪除/重新分配項目。 我懷疑是會有一個回調/偶數處理程序,它會被異步觸發(可能作為XNA 繪制等循環的一部分),並且正在編輯列表 - 這實際上是導致這個問題作為競爭條件。
要檢查是否是這種情況,請在操作列表的位置周圍放置一些調試/跟蹤輸出,並查看它是否曾經(特別是在異常之前)在控制台輸出的同時運行操作代碼:
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
(即不是個人/離散的操作 - 而是工作單位)
我使用while( collection.count >0)
不是foreach
,然后使用collection[i]
。
我不知道這是否與OP有關,但我有同樣的錯誤,並在谷歌搜索期間找到了這個帖子。 我能夠通過在刪除循環中的元素后添加一個中斷來解決它。
foreach( Weapon activeWeapon in activeWeapons ){
if (activeWeapon.position.Z < activeWeapon.range)
{
activeWeapons.Remove(activeWeapon);
break; // Fixes error
}
else
{
activeWeapon.position += activeWeapon.velocity;
}
}
}
如果省略中斷,您將收到錯誤“InvalidOperationException:在實例化枚舉數后修改了集合”。
使用Break
可能是一種方式,但它可能會影響您的一系列操作。 在這種情況下我做的只是將foreach
轉換為傳統的for
循環
for(i=0; i < List.count; i++)
{
List.Remove();
i--;
}
這沒有任何問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.