2012-03-12 42 views
1

我知道在迭代它時我無法修改集合。InvalidOperationException:已修改集合

通常我會製作我想要迭代的集合的副本,然後迭代副本以避免錯誤。

我的程序;然而,對我正在嘗試製作副本的集合進行了很多快速修改。

錯誤是否會發生,因爲我正在修改父集合時正在創建副本?

我知道ConcurrentDictionary爲跨線程提供了某種鎖定機制。有沒有類似的東西可以用來防止這個錯誤?

// Original collection: 
    Dictionary<string, Enemy> Dict_Enemies = new Dictionary<string, Enemy>(); 

    // Copy of original collection: (this line throws the exception) 
    Dictionary<string, Enemy> Dict_Enemies_Copy = new Dictionary<string, Enemy>(Dict_Enemies); 
+0

一個[ConcurrentDictionary(http://msdn.microsoft.com/en-us/library/dd287191 .aspx)爲'Dict_Enemies'? – 2012-03-12 06:35:57

+0

當我使用ConcurrentDictionary時,我的程序似乎掛在通常會拋出異常的地方。也許我在其他地方有一個問題。 – 2012-03-12 06:47:50

+0

可以使用[ConcurrentDictionary.ToArray()](http://msdn.microsoft.com/zh-cn/library/dd287109.aspx)方法以*線程安全*方式複製它。看看我的答案。 – 2012-03-12 07:23:04

回答

2

嘗試使用ConcurrentDictionary代替Dict_Enemies以允許它從多個線程進行修改。然後,使用ToArray()方法做它的一個副本線程安全的操作:爲什麼不使用

// Original collection: 
var Dict_Enemies = new ConcurrentDictionary<string, Enemy>(); 

// Thread-safe copy: 
ICollection<KeyValuePair<string, Enemy>> Dict_Enemies_Copy = Dict_Enemies.ToArray(); 
+0

請注意,ConcurrentDictionary的處理本身並不重要 - 您必須更改某些代碼,因爲CD上的某些操作(例如添加)可能因爲併發問題而返回「false」 - 在這種情況下,您必須重試操作! CD很不錯,但是如果你還沒有封裝你的訪問權限,那麼就不會有這樣的問題 – Carsten 2012-03-12 07:21:42

+0

@CarstenKönig同意。切換到「ConcurrentDictionary」當然需要對項目添加/刪除的方式進行一些更改。但是,根據需求,[有多種方式可以解決此問題](http://msdn.microsoft.com/zh-cn/library/dd997369.aspx)。 – 2012-03-12 07:28:16

+0

我認爲這解決了我的問題,謝謝。當我從併發字典中移除一個密鑰時,我可以使用虛擬對象作爲'out'參數嗎?虛擬foo; Dict.TryRemove(key,out foo); – 2012-03-12 07:30:30

0

封裝這個詞典作爲一類的私有成員,並使用鎖(在兩地相同的鎖定對象,可能是字典本身),以確保寫入和副本不會同時出現時間。不要讓任何地方直接訪問字典。

0

但類似的代碼是perfeclty爲我工作.....你能給你更多的解釋你的代碼?

Dictionary<int, Test> dicOrg = new Dictionary<int, Test>();//Original 
    dicOrg.Add(1, new Test() {id= 1,name="name",add="add"}); 
    Dictionary<int, Test> dicCopy = new Dictionary<int,Test>(dicOrg);//Copy of dicOrg 
+0

我有多種方法可以同時刪除項目並向dicOriginal添加項目。 我有各種方法同時拷貝dicOriginal。 我在任何嘗試製作dicOriginal副本的地方都會遇到異常情況。 – 2012-03-12 07:02:17

1

一個Dictionary<K,V>不支持多個併發的作家,這意味着你必須已經有一個鎖。只要確保您在按住該鎖的同時創建副本。

+0

我沒有鎖定,因爲我不確定如何正確實施。如果我使用'lock(dictionary){// dosomething //}',是不是會導致我的程序的其他部分停止正常工作,因爲他們將無法訪問字典? – 2012-03-12 07:05:58

+0

我需要某種方式來鎖定字典,但有其他方法檢查鎖,等待它被解鎖,然後繼續。 – 2012-03-12 07:07:42

+0

我試圖鎖定副本,而我迭代它,但我仍然得到異常... – 2012-03-12 07:15:24