11

我正在尝试在循环中更新哈希表,但出现错误: System.InvalidOperationException: Collection was modified; 枚举操作可能无法执行。

private Hashtable htSettings_m = new Hashtable();
htSettings_m.Add("SizeWidth", "728");
htSettings_m.Add("SizeHeight", "450");
string sKey = "";
string sValue = "";
foreach (DictionaryEntry deEntry in htSettings_m)
{
    // Get value from Registry and assign to sValue.
    // ...
    // Change value in hashtable.
    sKey = deEntry.Key.ToString();
    htSettings_m[sKey] = sValue;
}

有没有办法解决它,或者可能有更好的数据结构来实现这个目的?

4

12 回答 12

14

您可以先将键集合读入另一个 IEnumerable 实例,然后在该列表上进行 foreach

        System.Collections.Hashtable ht = new System.Collections.Hashtable();

        ht.Add("test1", "test2");
        ht.Add("test3", "test4");

        List<string> keys = new List<string>();
        foreach (System.Collections.DictionaryEntry de in ht)
            keys.Add(de.Key.ToString());

        foreach(string key in keys)
        {
            ht[key] = DateTime.Now;
            Console.WriteLine(ht[key]);
        }
于 2008-11-28T22:10:37.420 回答
5

在概念上我会这样做:

Hashtable table = new Hashtable(); // ps, I would prefer the generic dictionary..
Hashtable updates = new Hashtable();

foreach (DictionaryEntry entry in table)
{
   // logic if something needs to change or nog
   if (needsUpdate)
   {
      updates.Add(key, newValue);
   }
}

// now do the actual update
foreach (DictionaryEntry upd in updates)
{
   table[upd.Key] = upd.Value;
}
于 2008-11-28T22:06:47.553 回答
3

如果您使用 Dictionary 而不是 Hashtable,以便知道键的类型,则复制 Keys 集合以避免此异常的最简单方法是:

foreach (string key in new List<string>(dictionary.Keys))

为什么你得到一个异常告诉你你已经修改了你正在迭代的集合,而实际上你没有?

在内部,Hashtable 类有一个版本字段。Add、Insert 和 Remove 方法会增加此版本。在 Hashtable 公开的任何集合上创建枚举器时,枚举器对象包括 Hashtable 的当前版本。枚举器的 MoveNext 方法检查枚举器的版本与 Hashtable 的版本,如果它们不相等,它会抛出您看到的 InvalidOperationException。

这是一种非常简单的机制,用于确定 Hashtable 是否已被修改。事实上,这有点太简单了。Keys 集合确实应该维护自己的版本,它的 GetEnumerator 方法应该将集合的版本保存在枚举器中,而不是 Hashtable 的版本。

这种方法还有另一个更微妙的设计缺陷。版本是 Int32。UpdateVersion 方法不进行边界检查。因此,如果您对 Hashtable 进行了正确数量的修改(2 次Int32.MaxValue,给予或接受),那么即使您在创建 Hashtable 后从根本上更改了 Hashtable,也有可能使 Hashtable 上的版本和枚举数相同。枚举器。因此,即使 MoveNext 方法应该抛出异常,它也不会抛出异常,您会得到意想不到的结果。

于 2008-11-29T04:23:50.427 回答
2

最简单的方法是将键复制到单独的集合中,然后对其进行迭代。

您使用的是 .NET 3.5 吗?如果是这样,LINQ 会让事情变得更容易一些。

于 2008-11-28T22:15:10.670 回答
2

关键部分是ToArray()方法

var dictionary = new Dictionary<string, string>();
foreach(var key in dictionary.Keys.ToArray())
{
    dictionary[key] = "new value";
}
于 2010-03-19T11:23:24.010 回答
1

在枚举集合时,您不能更改存储在集合中的项目集,因为在大多数情况下,这会使迭代器变得非常困难。考虑集合代表一棵平衡树的情况,并且在插入后很可能会经历旋转。枚举将没有合理的方法来跟踪它所看到的内容。

但是,如果您只是尝试更新值,那么您可以编写:

deEntry.Value = sValue

在此处更新值对枚举器没有影响。

于 2008-11-28T22:06:28.927 回答
0

这取决于您为什么要遍历哈希表中的项目。但是您可能可以遍历键。所以

foreach (String sKey in htSettings_m.Keys)
{   // Get value from Registry and assign to sValue.
    // ...    
    // Change value in hashtable.
    htSettings_m[sKey] = sValue;
}

另一种选择是创建一个新的 HashTable。迭代第一个,同时将项目添加到第二个,然后用新的替换原来的。
不过,遍历键需要较少的对象分配。

于 2008-11-28T22:13:41.203 回答
0

这就是我在字典中的做法;将 dict 中的每个值重置为 false:

Dictionary<string,bool> dict = new Dictionary<string,bool>();

for (int i = 0; i < dict.Count; i++)
{
    string key = dict.ElementAt(i).Key;
    dict[key] = false;
}
于 2010-08-12T18:25:05.927 回答
0
List<string> keyList = htSettings_m.Keys.Cast<string>().ToList();
foreach (string key in keyList) {

它与其他答案相同,但我喜欢一行来获取密钥。

于 2013-03-29T18:44:57.867 回答
0

将其转换为数组:

private Hashtable htSettings_m = new Hashtable();
htSettings_m.Add("SizeWidth", "728");
htSettings_m.Add("SizeHeight", "450");
string sKey = "";
string sValue = "";

ArrayList htSettings_ary = new ArrayList(htSettings_m.Keys)
foreach (DictionaryEntry deEntry in htSettings_ary)
{
    // Get value from Registry and assign to sValue.
    // ...
    // Change value in hashtable.
    sKey = deEntry.Key.ToString();
    htSettings_m[sKey] = sValue;
}
于 2015-03-11T19:59:22.410 回答
-1
private Hashtable htSettings_m = new Hashtable();

htSettings_m.Add("SizeWidth", "728");    
htSettings_m.Add("SizeHeight", "450");    
string sValue = "";    
foreach (string sKey in htSettings_m.Keys)    
{    
    // Get value from Registry and assign to sValue    
    // ...    
    // Change value in hashtable.    
    htSettings_m[sKey] = sValue;    
}
于 2008-11-28T22:11:12.957 回答
-4

也许您可以使用 Hashtable.Keys 集合?在更改 Hashtable 时,可能可以进行枚举。但这只是猜测...

于 2008-11-28T22:10:11.133 回答