with values through loop keys from example array c# data-structures loops hashtable

values - ¿Cómo actualizar la hashtable C#en un bucle?



hashtable using (12)

En concepto, yo haría:

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

Estoy intentando actualizar una tabla hash en un bucle pero obteniendo un error: System.InvalidOperationException: la colección se modificó; la operación de enumeración no se puede ejecutar.

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

¿Hay alguna forma de evitarlo o tal vez hay una mejor estructura de datos para tal fin?


En primer lugar, podría leer la colección de claves en otra instancia de IEnumerable, y luego enfocarse en esa lista

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


La forma más simple es copiar las claves en una colección separada, luego iterar a través de eso.

¿Estás usando .NET 3.5? Si es así, LINQ hace las cosas un poco más fáciles.


No puede cambiar el conjunto de elementos almacenados en una colección mientras está enumerando sobre ella, ya que eso dificulta mucho la vida del iterador en la mayoría de los casos. Considere el caso en que la colección representa un árbol equilibrado, y bien puede sufrir rotaciones después de un inserto. El enumerado no tendría una forma plausible de hacer un seguimiento de lo que ha visto.

Sin embargo, si solo intentas actualizar el valor, puedes escribir:

deEntry.Value = sValue

Actualizar el valor aquí no tiene impacto en el enumerador.


Tal vez puedas usar la colección Hashtable.Keys? Enumerando a través de eso podría ser posible al cambiar la Hashtable. Pero es solo una suposición ...


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


Si está utilizando un diccionario en lugar de una tabla Hash, de modo que se conoce el tipo de claves, la forma más fácil de hacer una copia de la colección de claves para evitar esta excepción es:

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

¿Por qué recibes una excepción diciéndote que has modificado la colección sobre la que estás iterando, cuando en realidad no la has modificado?

Internamente, la clase Hashtable tiene un campo de versión. Los métodos Agregar, Insertar y Eliminar incrementan esta versión. Cuando crea un enumerador en cualquiera de las colecciones que expone el Hashtable, el objeto enumerador incluye la versión actual de Hashtable. El método MoveNext del enumerador comprueba la versión del enumerador frente a la Hashtable, y si no son iguales, arroja la InvalidOperationException que está viendo.

Este es un mecanismo muy simple para determinar si la Hashtable ha sido modificada o no. De hecho, es un poco demasiado simple. La colección Keys realmente debería mantener su propia versión, y su método GetEnumerator debería guardar la versión de la colección en el enumerador, no la versión de la Hashtable.

Hay otro defecto de diseño más sutil en este enfoque. La versión es un Int32. El método UpdateVersion no verifica límites. Por lo tanto, es posible, si realiza exactamente el número correcto de modificaciones en la Hashtable (2 veces Int32.MaxValue , más o menos), para que la versión en la Hashtable y el enumerador sea la misma aunque haya cambiado radicalmente la Hashtable desde la creación del enumerador. Por lo tanto, el método MoveNext no arrojará la excepción aunque debería hacerlo, y obtendrá resultados inesperados.


Así es como lo hice dentro de un diccionario; restablece cada valor en dict a falso:

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


Depende de por qué estás recorriendo los elementos en la tabla hash. Pero probablemente puedas iterar a través de las teclas. Asi que

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

La otra opción es crear una nueva HashTable. Itere a través del primero mientras agrega elementos al segundo y luego reemplace el original por el nuevo.
Sin embargo, el bucle a través de las teclas requiere menos asignaciones de objetos.


La parte clave es el método ToArray ()

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


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

Es lo mismo que las otras respuestas, pero me gusta la línea para obtener las claves.


Convierta a una matriz:

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