代码之家  ›  专栏  ›  技术社区  ›  z-boss

如何在循环中更新C#哈希表?

  •  9
  • z-boss  · 技术社区  · 16 年前

    我试图更新循环中的哈希表,但出现错误:System.InvalidOperationException:集合已修改;枚举操作不能执行。

    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;
    }
    

    是否有办法解决这个问题,或者是否有更好的数据结构用于此目的?

    12 回复  |  直到 15 年前
        1
  •  14
  •   keithwarren7    16 年前

    您可以先将密钥集合读入另一个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]);
            }
    
        2
  •  5
  •   Davy Landman    16 年前

    在概念上,我会:

    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;
    }
    
        3
  •  3
  •   Robert Rossney    16 年前

    如果使用字典而不是哈希表,以便知道键的类型,那么创建键集合副本以避免此异常的最简单方法是:

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

    为什么会出现一个异常,告诉您您已经修改了正在迭代的集合,而实际上您还没有修改?

    这种方法还有另一个更微妙的设计缺陷。该版本是一个Int32。UpdateVersion方法不进行边界检查。因此,如果您对哈希表进行了正确数量的修改(2次),这是可能的 Int32.MaxValue ,give或take),使哈希表和枚举器上的版本相同,即使创建枚举器后已彻底更改了哈希表。因此,MoveNext方法不会抛出异常,即使它应该抛出异常,您也会得到意外的结果。

        4
  •  2
  •   Jon Skeet    16 年前

    最简单的方法是将密钥复制到单独的集合中,然后迭代该集合。

    您正在使用.NET3.5吗?如果是这样,LINQ会让事情变得简单一点。

        5
  •  2
  •   Lars    11 年前

    ToArray()

    var dictionary = new Dictionary<string, string>();
    foreach(var key in dictionary.Keys.ToArray())
    {
        dictionary[key] = "new value";
    }
    
        6
  •  1
  •   Rob Walker    16 年前

    在对集合进行枚举时,不能更改集合中存储的项集,因为在大多数情况下,这使得迭代器的工作非常困难。考虑集合表示平衡树的情况,并且可以在插入之后进行旋转。列举者没有任何合理的方法来记录它所看到的一切。

    deEntry.Value = sValue
    

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

        7
  •  0
  •   brainimus user417509    13 年前

    这是我在字典里做的;将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;
    }
    
        8
  •  0
  •   Lars    11 年前

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

    另一个选项是创建一个新的哈希表。迭代第一个,同时向第二个添加项目,然后用新项目替换原始项目。
    不过,循环通过键需要更少的对象分配。

        9
  •  0
  •   Jess    11 年前
    List<string> keyList = htSettings_m.Keys.Cast<string>().ToList();
    foreach (string key in keyList) {
    

        10
  •  0
  •   Slogmeister Extraordinaire Andre Miller    9 年前

    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;
    }
    
        11
  •  -1
  •   Jon Skeet    16 年前
    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;    
    }
    
        12
  •  -4
  •   Vilx-    16 年前

    也许你可以使用Hashtable.Keys集合?在更改哈希表时,可能会枚举该值。但这只是一个猜测。。。