簡體   English   中英

奇怪的“集合在枚舉器實例化后被修改”異常

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM