11

ループでハッシュテーブルを更新しようとしていますが、エラーが発生します: 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;
}

それを回避する方法はありますか、それともそのような目的のためのより良いデータ構造がありますか?

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

ハッシュテーブルの代わりにディクショナリを使用していて、キーの型がわかっている場合、この例外を回避するために 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 のバージョンと列挙子が同じになる可能性があります。列挙子。そのため、MoveNext メソッドは例外をスローする必要がありますが、スローせず、予期しない結果が得られます。

于 2008-11-29T04:23:50.427 に答える
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 に答える
2

最も簡単な方法は、キーを別のコレクションにコピーし、代わりにそれを反復処理することです。

.NET 3.5 を使用していますか? もしそうなら、LINQ は物事を少し簡単にします。

于 2008-11-28T22:15:10.670 に答える
1

コレクションを列挙している間は、コレクションに格納されているアイテムのセットを変更することはできません。これは、ほとんどの場合、反復子にとって非常に困難になるためです。コレクションがバランスの取れたツリーを表し、挿入後にローテーションを受ける可能性がある場合を考えてみましょう。列挙には、見たものを追跡するもっともらしい方法がありません。

ただし、値を更新しようとしているだけの場合は、次のように記述できます。

deEntry.Value = sValue

ここで値を更新しても、列挙子には影響しません。

于 2008-11-28T22:06:28.927 に答える
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

それを配列に変換します。

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 に答える
0

ハッシュテーブル内のアイテムをループしている理由によって異なります。ただし、代わりにキーを反復処理できる可能性があります。そう

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

もう 1 つのオプションは、新しい HashTable を作成することです。2 番目に項目を追加しながら最初の項目を反復処理してから、元の項目を新しい項目に置き換えます。
ただし、キーをループすると、必要なオブジェクトの割り当てが少なくなります。

于 2008-11-28T22:13:41.203 に答える
0
List<string> keyList = htSettings_m.Keys.Cast<string>().ToList();
foreach (string key in keyList) {

他の回答と同じですが、キーを取得するための1行が好きです。

于 2013-03-29T18:44:57.867 に答える
-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 コレクションを使用できますか? ハッシュテーブルを変更しているときに、それを列挙することが可能になる場合があります。しかし、それは推測にすぎません...

于 2008-11-28T22:10:11.133 に答える