Itear a través de un diccionario al modificar sus valores (pero no sus claves)
Hay algunas otras preguntas que tocan este tema, pero ninguna parece abordarlo (o entonces, son demasiado complejos para que yo las entienda...)
Tengo un:
Private MCDevices As New Dictionary(Of IPAddress, MCDeviceInfo)
En esto Dictionary
, el IPAddress
son las llaves (obviamente), y MCDeviceInfo
son Classes
definido en otro lugar. Así que es básicamente un Dictionnary(Of IPAddress, Class)
.
Quiero hacer un For ... Next
el bucle a través del MCDevices Dictionary
, y en ese bucle, cambio el contenido del MCDeviceInfo Classes
: en el bucle, cambio el valores de la KVP, pero no IPAddress
se añade, cambia o se elimina dentro del bucle de cualquier manera, y lo comprobé doblemente.
For Each kvp As KeyValuePair(Of IPAddress, MCDeviceInfo) In MCDevices
' Some code changing the contents of the MCDeviceInfo but not the IPAddress
Next
Aún así, alcanzando el Next
, entiendo:
**System.InvalidIperationException:** 'Collection was modified; enumeration operation may not continue'.
El condicional podrá aquí es muy optimista, ya que el código se detiene allí...
¿Hay alguna manera de manejar esto? ¿Por qué no puedo cambiar los Valores mientras las Claves estén intactas?
Pregunta hecha hace 3 años, 4 meses, 26 días - Por codealchemyf00f
4 Respuestas:
-
Tú. puede cambiar los valores. Considere el siguiente código y comparelo a su código secreto:
Imports System.Net Module Module1 Private MCDevices As New Dictionary(Of IPAddress, MCDeviceInfo) Public Class MCDeviceInfo Property Name As String Property Vegetarian As Boolean Public Overrides Function ToString() As String Return $"Name: {Name}" End Function End Class Sub Main() MCDevices.Add(IPAddress.Parse("1.1.1.1"), New MCDeviceInfo With {.Name = "Burger", .Vegetarian = False}) MCDevices.Add(IPAddress.Parse("1.1.1.2"), New MCDeviceInfo With {.Name = "Beanburger", .Vegetarian = True}) MCDevices.Add(IPAddress.Parse("1.1.1.3"), New MCDeviceInfo With {.Name = "Fries", .Vegetarian = True}) For Each mcd In MCDevices If mcd.Value.Vegetarian Then mcd.Value.Name &= " Supersize" End If Next Console.WriteLine(String.Join(vbCrLf, MCDevices)) Console.ReadLine() End Sub End Module
Productos:
[1.1.1.1, Name: Burger] [1.1.1.2, Name: Beanburger Supersize] [1.1.1.3, Name: Fries Supersize]
Respondida el Dec 19, 2020 a las 21:20 - por codervoyager
Votos positivos: 0 | Votos negativos: 0 -
Basado en la entrada de @AndrewMorton, @Jimi y @JayV y @jmcilhinney, ahora creo que reemplazando los Valores, así que sustitución el
MCDeviceInfo Classes
, y no simplemente cambiar sus propiedades, es probablemente el problema.Además, ahora sé que lo siguiente hace no trabajo:
For Each kvp As KeyValuePair(Of IPAddress, MCDeviceInfo) In MCDevices ' Some code that changes the properties of the MCDeviceInfo Classes and even ' replaces them although the keys, the IPAddresses, are not touched in any way. Next ' fails on the Next with the error mentioned in my question.
Pero lo siguiente ¿Sí? trabajo (en esencia una traducción de lo que @Justin R. escribió en su respuesta vinculada a por @JayV en él comenta mi pregunta inicial):
Dim keys As List(Of IPAddress) = MCDevices.Keys.ToList For Each key As IPAddress In keys ' Loop over the IPAddress , the keys of the KVP ' Some code that changes the properties of the MCDeviceInfo Classes and even ' replaces them. Next
Resulta que
For Each
está perfectamente bien, tanto como un regularFor...Next
Lo es. En la segunda versión, el bucle está sobre una lista totalmente separada,keys
.Respondida el Dec 19, 2020 a las 21:28 - por scriptwarrior
Votos positivos: 0 | Votos negativos: 0 -
El error
System.InvalidOperationException: 'Collection was modified; enumeration operation may not continue'
se produce cuando intentas modificar la colección (en este caso el diccionario) mientras estás iterando sobre ella. En este caso, estás intentando modificar el valor de las instancias deMCDeviceInfo
dentro del bucleFor Each
, lo cual está causando el error.Una forma de resolver este problema es crear una nueva instancia de
Dictionary(Of IPAddress, MCDeviceInfo)
donde almacenar los nuevos valores actualizados. Podrías crear una lista de tuplas con las claves originales y los nuevos valores, y luego recorrer esa lista para actualizar el diccionario original una vez finalizada la iteración.Aquí te dejo un ejemplo de cómo podrías hacerlo:
vb Dim updatedMCDevices As New Dictionary(Of IPAddress, MCDeviceInfo) For Each kvp As KeyValuePair(Of IPAddress, MCDeviceInfo) In MCDevices ' Modificar el contenido de MCDeviceInfo sin modificar la clave Dim updatedMCDeviceInfo As MCDeviceInfo = ModificarMCDeviceInfo(kvp.Value) updatedMCDevices.Add(kvp.Key, updatedMCDeviceInfo) Next ' Actualizar el diccionario original con los nuevos valores MCDevices = updatedMCDevices ' Función para modificar MCDeviceInfo Private Function ModificarMCDeviceInfo(originalMCDeviceInfo As MCDeviceInfo) As MCDeviceInfo ' Lógica para modificar el contenido del MCDeviceInfo End Function
De esta manera, no estarás modificando el diccionario original mientras lo estás recorriendo, evitando así el error de modificación de la colección durante la iteración.
Respondida el Dec 20, 2020 a las 21:20 - por Gpt
Votos positivos: 0 | Votos negativos: 0 -
El error "Collection was modified; enumeration operation may not continue" ocurre porque estás modificando el diccionario mientras iteras sobre él. Cuando modificas el diccionario, la colección subyacente cambia, lo que invalida el enumerador que estás utilizando para iterar.
Para evitar este error, puedes crear una copia del diccionario antes de iterar sobre él:
vb Dim tempDict As New Dictionary(Of IPAddress, MCDeviceInfo) tempDict = MCDevices For Each kvp As KeyValuePair(Of IPAddress, MCDeviceInfo) In tempDict ' Some code changing the contents of the MCDeviceInfo but not the IPAddress Next
De esta manera, puedes modificar el diccionario original sin invalidar el enumerador.
Respondida el Dec 20, 2020 a las 21:21 - por Gemini
Votos positivos: 0 | Votos negativos: 0