2010-08-17 8 views
21
foreach(BruteforceEntry be in Entries.Values) 
{ 
    if (be.AddedTimeRemove <= now) 
     Entries.Remove(be.IPAddress); 
    else if (be.Unbantime <= now && be.Unbantime.Day == DateTime.Now.Day) 
     Entries.Remove(be.IPAddress); 
} 

generado una excepción:Modificar un diccionario que estoy iteración a través de

Collection fue modificado; la operación de enumeración no se puede ejecutar.

Por alguna razón, ya no es así.

Sé que no puede eliminar algo, mientras lo itera de esta manera. Mi pregunta es: ¿cómo lo resuelvo?

Respuesta

34

No puede modificar una colección sobre la que está iterando. En este caso, una solución mucho mejor sería la creación de una lista de entradas de eliminar mediante la iteración en el diccionario, y luego pasar sobre ese lista, la eliminación de las entradas del diccionario:

List<string> removals = new List<string>();      
DateTime now = DateTime.Now; 
foreach(BruteforceEntry be in Entries.Values) 
{ 
    if (be.AddedTimeRemove <= now || 
     (be.Unbantime <= now && be.Unbantime.Day == DateTime.Now.Day)) 
    { 
     removals.Add(be.IPAddress); 
    } 
} 
foreach (string address in removals) 
{ 
    Entries.Remove(address); 
} 

Tenga en cuenta que si que está utilizando .NET 3.5, se puede utilizar una consulta LINQ para expresar la primera parte:

List<string> removals = (from be in Entries.Values 
         where be.AddedTimeRemove <= now || 
           (be.Unbantime <= now && 
           be.Unbantime.Day == DateTime.Now.Day) 
         select be.IPAddress).ToList(); 
+1

Muchas gracias. Tengo 1 pregunta, ¿te gusta esto más que simplemente iterar a través de una copia, utilizando .ToList() ya que es una edición más pequeña. – Basser

+1

@Basser: Bueno, para empezar, es probable que tenga una huella de memoria más pequeña. También se repite una única vez en toda la colección: la solución actual se repite una vez para crear la lista y luego itera sobre esa lista. No me malinterprete, funcionará ... prefiero este enfoque. –

+0

Bueno, acabo de enterarme que un usuario de SO superior respondió mi pregunta, ¡por eso pensé que podría preguntarle! ¡Supongo que usaré este método, ya que estás en lo correcto! Gracias de nuevo. Todavía no soy muy bueno con las colecciones, sigo aprendiendo. – Basser

1

No puede modificar la colección al iterar sobre ella con foreach. En cambio, itere sobre él con un bucle for.

+2

Si vas a ser la eliminación de elementos de la colección, asegúrese de iterar sobre ella en inverso (de longitud-1 a 0) y no de 0 a longitud-1 –

+1

Es mejor que itere hacia atrás si está eliminando elementos y actualiza su variable de incremento en consecuencia si lo agrega. Esto es propenso a los errores. – Marc

+5

Iterar un * diccionario * con un bucle for es un tanto complicado de todos modos ... –

2

puede cambiar foreach(BruteforceEntry be in Entries.Values) a foreach(BruteforceEntry be in new List<BruteforceEntry>(Entries.Values))

de esa manera usted no modifique su colección, pero ra hay una copia de eso.

+0

Gracias, esto funcionaría si alguien más no respondiera. – Basser

+0

Esto no funcionará porque todavía está obteniendo un iterador de la Lista <>. Es el iterador, no la colección, lo que está causando el problema. –

+0

Seguro que funciona, no está eliminando del iterador List <>, está eliminando del diccionario <> iterator. La Lista <> enumera el iterador completo del Diccionario <> antes de la primera eliminación del diccionario. –

0

ebullición abajo de su problema ...

foreach(... ... in Entries.Values) 
{ 
     Entries.Remove(...); 

} 

Como los otros han dicho que va a modificar el iterador mientras que la iteración.

Puede, como dijo @David, utilizar un bucle for en su lugar, pero asegúrese de comenzar al final (iteración inversa).

8

En pocas palabras: no se puede eliminar una entrada de una colección mientras se itera sobre ella.

Una posible solución es crear una copia superficial de la colección (por ejemplo, utilizando ToList) y pasar sobre ese:

foreach(BruteforceEntry be in Entries.Values.ToList()) 
{ 
    // modify the original collection 
} 
+0

Gracias, esto resolvió mi pregunta. – Basser

+0

Esto no funcionará porque todavía está obteniendo un iterador de la Lista <>. Es el iterador, no la colección, lo que está causando el problema. –

+0

Mi solución fue solo un ejemplo de solución. En términos de rendimiento y claridad, le sugiero que adopte la solución de Jon;) – digEmAll

2

Parece que tu pregunta es acerca de por qué una excepción es no ser lanzado en solía ser. Como dicen las otras respuestas, generalmente no puede cambiar una colección a través de la cual está iterando, pero está iterando sobre la colección Values, que, en mi opinión, es una copia de los valores en el diccionario, en lugar de referirse a la colección principal del diccionario sí mismo. Entonces ya no tiene el problema de iterar y modificar lo mismo.

1

Este (en mi opinión) es la forma más fácil:

Dictionary<String, String> A = new Dictionary<string, string>(); //Example Dictionary 
A.Add("A", "A"); //Example Values 
A.Add("B", "B"); 
A.Add("C", "C"); 

for (int i = A.Count - 1; i >= 0; i--) //Loop backwards so you can remove elements. 
{ 
    KeyValuePair<String, String> KeyValue = A.ElementAt(i); //Get current Element. 
    if (KeyValue.Value == "B") A.Remove(KeyValue.Key); 
} 

En su caso:

for (int i = Entries.Count - 1; i >= 0; i--) 
{ 
    KeyValuePair<String, BruteforceEntry> KeyValue = Entries.ElementAt(i); 
    if (KeyValue.Value.AddedTimeRemove <= now) 
     Entries.Remove(KeyValue.Key); 
    else if (KeyValue.Value.Unbantime <= now && KeyValue.Value.Unbantime.Day == DateTime.Now.Day) 
     Entries.Remove(KeyValue.Key); 
} 
+1

-1 Si bien esto puede funcionar para algunas implementaciones de .NET, la clase 'Dictionary ' no ** garantiza ** que el orden de sus elementos (cuando se itera como 'IEnumerable > ') no se modifica cuando se modifica el diccionario. – Ergwun

+1

desde http://msdn.microsoft.com/en-us/library/xfhwa508.aspx: "A los efectos de la enumeración, cada elemento del diccionario se trata como una estructura KeyValuePair que representa un valor y su clave. El orden en que se devuelven los elementos no está definido." – Ergwun

+1

Ahh, no sabía esto, ¡gracias por la aclaración! – Blam

Cuestiones relacionadas