2010-11-15 46 views
9

我聲明瞭一個Dictionary類型的對象,並嘗試添加一些項目到它。但我無法修改該物品的價值。鑰匙不可修改是合理的,但爲什麼不能修改?謝謝。爲什麼.NET Dictionary <TKey,TValue>是不可變的?

Dictionary<string, string> dict = new Dictionary<string, string>(); 
    dict.Add("1", "bob"); 
    dict.Add("2", "jack"); 
    dict.Add("3", "wtf"); 
    foreach (string key in dict.Keys) 
    { 
     dict[key] = "changed"; //System.InvalidOperationException: Collection was modified 
    } 

回答

14

字典本身並不是不可變的。但是在foreach循環中枚舉它時不能更改字典。

下面的鏈接進一步閱讀:Why is The Iteration Variable in a C# foreach statement read-only?

+2

換句話說,當前迭代的集合是不可變的 – abatishchev 2010-11-15 10:55:31

+1

@abatishchev,不應修改的對象與無法修改的對象之間存在差異。術語_immutable_指的是後者,而正在迭代的集合是前者。 – 2013-05-21 14:06:35

17

你不允許修改你迭代的foreach循環集合。這與字典無關 - dict[key] = "value";foreach循環之外完美無缺。

2

Dictionary不是一成不變(第一,如果是這樣,你就無法Add的話)。

的問題是,你想在遍歷它修改集合- 一個foreach塊中使用它,你不能改變的集合。

更改foreach以外的值將有效。

+0

你不能使用'int'索引來訪問字典,除非它實際上是一個'Dictionary '。 – LukeH 2010-11-15 10:22:12

+0

@LukeH - 很對。正在考慮其他集合... – Oded 2010-11-15 10:24:26

4

它不是一成不變的,你可以改變它,它只是,如果你修改集合當前迭代器變爲無效。你可以「解決」這迫使迭代器修改

foreach (string key in new List<string>(dict.Keys)) 
{ 
    dict[key] = "changed"; //System.InvalidOperationException: Collection was modified 
} 
1

正試圖在你迭代它同時修改集合的集合之前完成。這是不允許的。在foreach循環中移動下一個枚舉器的方法拋出異常。

1

正如@Femaref所提到的,在foreach循環內迭代時,不能更改字典。另一個解決辦法是使用循環和使用下面的代碼來改變它

for (int i = 0; i < dict.Count; i++) 
{ 
    var key = dict.Keys.ElementAt(i); 
    dict[key] = "changed"; 
} 

注意:您要使用LINQ這一點。

+0

對於大型字典無效,但可能可行。 – 2010-11-15 13:26:14

+0

Dicationaries無序。這在某些情況下可能會失敗。 – SLaks 2010-11-15 13:49:03

+0

同樣.... ....這個邏輯獨立於字典中元素的順序。 – 2010-11-16 11:02:14

2

我能想到的一個比喻就是試圖在坐在樹枝上時剪下一根樹枝。所以它被認爲是不安全的。

另一種方法是使用for循環或克隆列表。

1

dict.Keys轉換爲數組。

然後做這個循環。

如果修改集合,它會拋出異常。

7

您使用的術語immutable錯誤。它通常用於內部狀態在初始化後不會改變的對象。 Dictionary<TKey, TValue>是可變的。它在枚舉期間有人試圖修改它時拋出異常是一個明確實現的行爲。

您可能會困惑,爲什麼枚舉會改變,當你只改變一個值。這還不包括在其他答案中。

那麼,當你做

dict[key] = "something"; 

枚舉變化如果關鍵不尚未存在,因爲它會在這種情況下被添加,導致枚舉改變。當然,字典實現可以首先檢查並且如果密鑰已經存在則允許修改,但是我想它遵循原理提前失敗,經常失敗以改進應用程序的總體完整性。

1

微軟決定,如果有多次傳遞通過,iEnumerable支持Reset方法的對象應該返回完全相同的數據。這是一個有用的保證,如果你希望例如產生一個包含所有項目的字符串(第一遍可以統計所有項目的長度,第二遍可以連接它們)。由於即使更改字典項目的價值也會違反該保證,因此被禁止。如果實際上嘗試第二次通過集合,那麼對字典值進行更改可能會很好,但這不是微軟設計的方式。另外,我並不熟悉字典的內部實現,但它可能會將值更改作爲刪除和插入來處理。如果這樣做,那肯定會破壞統計員。

相關問題