Frage

Ich versuche, eine Hash-Tabelle in einer Schleife zu aktualisieren, sondern erhalte eine Fehlermeldung: System.InvalidOperationException: Die Auflistung wurde geändert; Aufzählung kann möglicherweise nicht ausgeführt.

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

Gibt es Weise um sie oder vielleicht gibt es eine bessere Datenstruktur für einen solchen Zweck?

War es hilfreich?

Lösung

Sie die Sammlung von Schlüsseln in einer anderen IEnumerable Instanz zuerst lesen können, dann foreach über diese Liste

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

Andere Tipps

Im Konzept, das ich tun würde:

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

Wenn Sie ein Wörterbuch anstelle eines Hashtable verwenden, so dass die Art der Schlüssel bekannt ist, ist der einfachste Weg, um eine Kopie der Schlüssel Sammlung zu machen, diese Ausnahme zu vermeiden ist:

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

Warum sind Sie immer eine Ausnahme, die Sie sagen, dass Sie die Sammlung geändert haben Sie iterieren, wenn in der Tat haben Sie nicht?

Intern hat die Klasse Hashtable ein Versionsfeld. Das Hinzufügen, Einfügen und Entfernen Methoden, um diese Version zu erhöhen. Wenn Sie einen Enumerator auf einem der Sammlungen zu erstellen, die die Hashtable aussetzt, enthält das Enumeratorobjekt die aktuelle Version des Hashtable. Die Methode Movenext des enumerator prüft die enumerator-Version gegen die Hashtable ist, und wenn sie nicht gleich sind, dann wirft es die InvalidOperationException Sie sehen.

Dies ist ein sehr einfacher Mechanismus zur Bestimmung, ob der Hashtable modifiziert wurde. In der Tat ist es ein wenig zu einfach. Die Keys Sammlung sollte wirklich seine eigene Version halten und seine GetEnumerator-Methode sollte die Sammlung der Version in der Enumerator retten, nicht die Hashtable-Version.

Es gibt eine andere, subtilere Design Defekt in diesem Ansatz. Die Version ist ein Int32. Die Updateversion Methode hat keine Grenzen überprüft. Es ist daher möglich, wenn Sie genau die richtige Anzahl von Änderungen an die Hashtable machen (2-mal Int32.MaxValue, geben oder nehmen), für die Version auf der Hashtable und den enumerator gleich zu sein, obwohl Sie radikal die Hashtable geändert haben, seit der Erstellung der Enumerator. So ist die Movenext-Methode wird nicht die Ausnahme aus, obwohl es sollte, und Sie werden unerwartete Ergebnisse erhalten.

Der einfachste Weg ist den Schlüssel in eine getrennte Sammlung zu kopieren, iterieren dann durch, dass statt.

Sind Sie mit .NET 3.5? Wenn ja, macht LINQ Dinge ein wenig einfacher.

Der wichtigste Teil ist die ToArray () Methode

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

Sie können nicht die Menge von Elementen in einer Sammlung gespeichert ändern, während Sie über sie sind aufzählt, denn das Leben für den Iterator in den meisten Fällen sehr schwierig macht. Betrachten wir den Fall, wo die Sammlung einen ausgeglichenen Baum darstellt, und kann gut unterziehen Umdrehungen nach einem Einsatz. Die Aufzählung würde keinen plausiblen Weg hat Spur zu halten, was es gesehen hat.

Wenn Sie jedoch nur versuchen, den Wert zu aktualisieren, dann können Sie schreiben:

deEntry.Value = sValue

den Wert hier Aktualisierung hat keine Auswirkungen auf die enumerator.

Dies ist, wie ich es in einem Wörterbuch tat; jeden Wert in dict auf false setzt:

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

Es hängt davon ab, warum Sie durch die Elemente in der Hash-Tabelle sind Looping. Aber Sie würden wahrscheinlich in der Lage sein, anstatt die Schlüssel iterieren throught. So

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

Die andere Option ist eine neue HashTable zu erstellen. Iteration durch die erste, während das Hinzufügen von Elementen zu der zweiten dann das Original mit dem neuen ersetzen.
Looping über die Tasten erfordert weniger Objekt Zuweisungen though.

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

Es ist das gleiche wie die anderen Antworten, aber Ich mag die eine Zeile die Schlüssel zu erhalten.

konvertieren es in ein Array:

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

Vielleicht können Sie Hashtable.Keys Sammlung verwenden? Aufzählen durch das könnte möglich sein, während die Hashtable zu verändern. Aber es ist nur eine Vermutung ...

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top