我想更新循环中的哈希表,但得到一个错误信息: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;
}

是否有它周围的方式或也许有用于该目的的一个较好的数据结构?

有帮助吗?

解决方案

您可以先阅读领取钥匙到另一个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]);
        }

其他提示

在概念我会做:

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

如果您使用的是字典,而不是一个Hashtable,使键的类型是已知的,最简单的方法,使键集合的副本,以避免这种情况的例外是:

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

为什么你得到一个异常告诉你,你已经修改了收集你遍历的时候,其实你没有?

在内部,Hashtable类具有版本字段。添加,插入,删除和方法增加此版本。当您在任何Hashtable的公开集合创建一个枚举,枚举器对象包括哈希表的当前版本。枚举的MoveNext方法检查枚举兑哈希表的版本,如果他们不相等时,它抛出你看到InvalidOperationException异常。

这是用于确定哈希表是否已经被修改了非常简单的机构。事实上,它是一个有点太简单了。在领取钥匙真的应该保持自己的版本,它的GetEnumerator方法应保存收集的版本中枚举,而不是哈希表的版本。

有在此方法中另一个,微妙的设计缺陷。该版本是一个Int32。该UpdateVersion方法确实没有边界检查。它因此可能的,如果你做完全修改Hashtable中的权数(2次Int32.MaxValue,给予或采取),用于在哈希表的版本和枚举是相同的,即使你已经彻底改变了哈希表因为创建枚举。因此,MoveNext方法不会抛出异常,即使它应该,你会得到意想不到的效果。

最简单的方法是通过将密钥复制到单独的收集,然后迭代来代替。

您使用.NET 3.5?如果是这样,LINQ使得事情稍微容易一些。

的关键部分是在 ToArray的()方式

var dictionary = new Dictionary<string, string>();
foreach(var key in dictionary.Keys.ToArray())
{
    dictionary[key] = "new value";
}

您不能改变设定存储在一个集合中正在枚举在它的项目,因为这使得在大多数情况下,迭代的生活非常困难。考虑其中收集代表一个平衡树,并插入后可能进行轮换的情况。该枚举必须保持跟踪它已经看到了。没有合理的方式。

不过,如果你只是想更新的价值,那么你可以这样写:

deEntry.Value = sValue

更新值这里对枚举没有影响。

这是我在词典中做到了;在字典的每一个值重置为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;
}

这取决于你为什么通过哈希表中的项目循环。但是,你可能可以迭代throught键代替。所以

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

另一个选项是创建新的哈希表。通过第一循环,同时将项目添加到第二个,然后用新的替换原来的。结果 通过按键循环需要较少的对象分配虽然。

List<string> keyList = htSettings_m.Keys.Cast<string>().ToList();
foreach (string key in keyList) {

有相同的其他的答案,但我喜欢的一条线,以获得密钥。

将其转换为一个数组:

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

也许你可以使用Hashtable.Keys收集?通过枚举而改变Hashtable中是可能的。但是,这只是一种猜测...

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top