2010-11-15 95 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方法的对象应该返回完全相同的数据。这是一个有用的保证,如果你希望例如产生一个包含所有项目的字符串(第一遍可以统计所有项目的长度,第二遍可以连接它们)。由于即使更改字典项目的价值也会违反该保证,因此被禁止。如果实际上尝试第二次通过集合,那么对字典值进行更改可能会很好,但这不是微软设计的方式。另外,我并不熟悉字典的内部实现,但它可能会将值更改作为删除和插入来处理。如果这样做,那肯定会破坏统计员。

相关问题