For Each List(Of String) System.InvalidOperationException

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 13 Antworten in diesem Thema. Der letzte Beitrag () ist von jvbsl.

    For Each List(Of String) System.InvalidOperationException

    Hallo liebe Community,

    ich habe ein Problem mit meine Konsolenanwendung. Ich habe auch schon das Internet auf Lösungen dursucht, bin aber leider nicht fündig geworden. In dieser Anwendung ist ein Loop eingebaut, das heißt, dass alles wiederholt wird, wenn jeder Schritt erledigt wurde. Leider habe ich nun ein Problem mit meiner Auflistung. Es wird bei jedem Durchgang die Liste neu geladen und am Ende gecleared. Trotzdem tritt der Fehler System.InvalidOperationException in der For Each auf (Um genauer zu sein, tritt der Fehler im nächsten Durchgang auf, wenn die Funktion ComparePattern True zurück gibt).

    Zusätzliche Informationen bei der Exception:
    Spoiler anzeigen

    Quellcode

    1. Ein Ausnahmefehler des Typs "System.InvalidOperationException" ist in mscorlib.dll aufgetreten.
    2. Zusätzliche Informationen: Die Auflistung wurde geändert. Der Enumerationsvorgang kann möglicherweise nicht ausgeführt werden.



    Betroffener Code: (Die Variable "Lines" ist dabei die List(Of String))
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Sub ReadDoc()
    2. Try
    3. Lines.AddRange(IO.File.ReadAllLines(memFile))
    4. Catch e As Exception
    5. Console.WriteLine(e.ToString())
    6. End Try
    7. For Each item In Lines
    8. Dim stringArray = item.Split({" ", " "}, StringSplitOptions.None)
    9. item = stringArray(0) & " " & stringArray(1)
    10. msg = stringArray(2)
    11. Console.WriteLine(item)
    12. ComparePattern(item)
    13. Next
    14. Lines.Clear()
    15. Main()
    16. End Sub



    Ich hoffe jemand von euch kann mir helfen.

    LG
    Quellcoder
    Projekte
    Man darf vielleicht ja die Items während die Schleife läuft verändern...

    Lass das hier mal weg und schau ob der Code durchläuft:
    item = stringArray(0) & " " & stringArray(1)
    "Gib einem Mann einen Fisch und du ernährst ihn für einen Tag. Lehre einen Mann zu fischen und du ernährst ihn für sein Leben."

    Wie debugge ich richtig? => Debuggen, Fehler finden und beseitigen
    Wie man VisualStudio nutzt? => VisualStudio richtig nutzen

    Quellcoder02 schrieb:

    item = stringArray(0) & " " & stringArray(1)

    Da wird innerhalb der Schleife der Wert verändert, versuch's mal anders:

    VB.NET-Quellcode

    1. For Each item In Lines
    2. Dim stringArray = item.Split({" ", " "}, StringSplitOptions.None)
    3. Dim NewItem = stringArray(0) & " " & stringArray(1)
    4. msg = stringArray(2)
    5. Console.WriteLine(NewItem)
    6. ComparePattern(NewItem)
    7. Next
    @us4711 danke für deine Antwort, es tritt allerdings immer noch der gleiche Fehler an der gleichen Stelle auf.

    Code:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. For Each item In Lines
    2. Dim stringArray = item.Split({" ", " "}, StringSplitOptions.None)
    3. Dim listItem = stringArray(0) & " " & stringArray(1)
    4. msg = stringArray(2)
    5. Console.WriteLine(listItem)
    6. ComparePattern(listItem)
    7. listItem = ""
    8. Next



    LG
    Projekte
    Dann kommentier doch mal alle Zeilen in der for-Schleife aus und reaktivier eine nach der anderen. Wo kommt der Fehler?

    Mal ne Unwissenheitszwischenfrage, wenn der Fehler nach der folgenden Stelle auftritt: Was ist und macht eigentlich ComparePattern?
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    VaporiZed schrieb:

    Dann kommentier doch mal alle Zeilen in der for-Schleife aus und reaktivier eine nach der anderen.


    Habe ich ausprobiert, allerdings kommt der Fehler nicht wenn ComparePattern() nicht der formatierte String in Form von listItem übergeben bekommt.

    VaporiZed schrieb:

    Was ist und macht eigentlich ComparePattern?


    ComparePattern ist eine Boolean Funktion die jeden Char von dem übergebenen String listItem mit einem vorgegebenem Format vergleicht. Das wird dann in ein Datum formatiert und wenn dieses Datum jetzt oder vergangenheit ist, wird eine andere externe Anwendung gestartet und das Item welches jetzt oder vergangenheit ist gelöscht(wobei das löschen auch nicht funktioniert).

    Zusammenhängender Code:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Sub ReadDoc()
    2. Try
    3. Lines.AddRange(IO.File.ReadAllLines(memFile))
    4. Catch e As Exception
    5. Console.WriteLine(e.ToString())
    6. End Try
    7. For Each item In Lines
    8. Dim stringArray = item.Split({" ", " "}, StringSplitOptions.None)
    9. Dim listItem = stringArray(0) & " " & stringArray(1)
    10. msg = stringArray(2)
    11. Console.WriteLine(listItem)
    12. ComparePattern(listItem)
    13. listItem = ""
    14. Next
    15. Lines.Clear()
    16. Main()
    17. End Sub
    18. Public Function ComparePattern(item As String) As Boolean
    19. With item
    20. For I2 As Integer = 0 To .Count - 1
    21. 'If .Count < 2 Then Continue For Else Exit For
    22. 'Dim i As String = item(I2).SubItems(1).Text
    23. If item.Length < 16 Then Continue For
    24. 'Datum
    25. If Not Char.IsDigit(item, 0) Then Continue For
    26. If Not Char.IsDigit(item, 1) Then Continue For
    27. If Not item.ElementAt(2) = "."c Then Continue For
    28. If Not Char.IsDigit(item, 3) Then Continue For
    29. If Not Char.IsDigit(item, 4) Then Continue For
    30. If Not item.ElementAt(5) = "."c Then Continue For
    31. If Not Char.IsDigit(item, 6) Then Continue For
    32. If Not Char.IsDigit(item, 7) Then Continue For
    33. If Not Char.IsDigit(item, 8) Then Continue For
    34. If Not Char.IsDigit(item, 9) Then Continue For
    35. If Not item.ElementAt(10) = " "c Then Continue For
    36. 'Uhrzeit
    37. If Not Char.IsDigit(item, 11) Then Continue For
    38. If Not Char.IsDigit(item, 12) Then Continue For
    39. If Not item.ElementAt(13) = ":"c Then Continue For
    40. If Not Char.IsDigit(item, 14) Then Continue For
    41. If Not Char.IsDigit(item, 15) Then Continue For
    42. If DateTime.Now.CompareTo(Date.Parse(item)) >= 0 Then
    43. Console.WriteLine(item, item, I2)
    44. Console.WriteLine("TRUE")
    45. If test4process() = False Then
    46. If Not String.IsNullOrWhiteSpace(AppPath) Then
    47. Try
    48. Console.WriteLine(AppPath)
    49. Process.Start(AppPath, vbNormalFocus)
    50. deleteItem(item & " " & msg)
    51. Return True
    52. Catch e As Exception
    53. Console.WriteLine(e.ToString())
    54. Return False
    55. End Try
    56. Else
    57. Try
    58. Process.Start("")
    59. deleteItem(item & " " & msg)
    60. Return True
    61. Catch ex As Exception
    62. Console.WriteLine("Exception: File not Found!" & vbNewLine & ex.ToString())
    63. Return False
    64. End Try
    65. End If
    66. Else
    67. deleteItem(item & " " & msg)
    68. End If
    69. End If
    70. Next
    71. Return False
    72. End With
    73. End Function
    74. Sub deleteItem(todelete As String) 'FixMe: Löscht alles und
    75. Console.WriteLine("Sleep: 3s")
    76. Thread.Sleep(3000)
    77. Dim IndexInt As Integer
    78. For Each legacyItm In Lines
    79. For i As Integer = 0 To Lines.Count - 1
    80. If legacyItm.Equals(todelete) Then
    81. IndexInt = i
    82. legacyItm = ""
    83. End If
    84. Next
    85. Next
    86. Lines.RemoveAt(IndexInt)
    87. IO.File.Delete(memFile)
    88. Dim fs As New FileStream(memFile, FileMode.OpenOrCreate)
    89. Dim sw As New StreamWriter(fs)
    90. sw.WriteLine(Lines)
    91. fs.Close()
    92. End Sub


    Projekte
    Lines.RemoveAt(IndexInt) in der deleteItem-Sub, die von der ComparePattern-Methode aufgerufen wird => never change a running for-each-loop. Die wird sauer, wenn da Items gelöscht werden.
    Ich überblick den ComparePattern-Code nur sehr grob. Aber warum versuchst Du nicht den String mittels CDate umzuwandeln oder per Parsing? Und warum muss der an die ComparePattern übergebende String char by char auf Datumsinhalt geprüft werden? Du scheinst den For-Schleifen-Char nur in einer einzigen Textausgabe zu verwenden. Ist das trotzdem relevant? Aber das ist ein anderes Thema.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „VaporiZed“ ()

    @VaporiZed das heißt also, dass ich das Item welches gelöscht werden soll, erst dann löschen darf, wenn die For Each Loop beendet ist? Habe das jetzt mal so umgesetzt, dass das Item zwischengespeichert wird und nach der For Each deletItem aufgerufen wird, falls die zwischenspeicher Variable nicht leer ist. Jetzt bekomm ich allerdings eine "System.ArgumentOutOfRangeException" geworfen.

    Code:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Dim toDelItm As String
    2. Sub deleteItem()
    3. Console.WriteLine("Sleep: 3s")
    4. Thread.Sleep(3000)
    5. Dim IndexInt As Integer
    6. For Each legacyItm In Lines
    7. For i As Integer = 1 To Lines.Count - 1
    8. If legacyItm.Equals(toDelItm) Then
    9. IndexInt = i
    10. legacyItm = ""
    11. End If
    12. Next
    13. Next
    14. Lines.RemoveAt(IndexInt)
    15. IO.File.Delete(memFile)
    16. Dim fs As New FileStream(memFile, FileMode.OpenOrCreate)
    17. Dim sw As New StreamWriter(fs)
    18. sw.WriteLine(Lines)
    19. fs.Close()
    20. End Sub



    LG
    Projekte
    @jvbsl: Ja, richtig. Damit der TE auch für die Zukunft was mitnehmen kann, bleib ich trotzdem mal dran.
    @Quellcoder02: Ich seh jetzt nur, dass Du die string-Variable aus der deleteItem-Methode statt als Parameter nun als quasi-globale Variable nutzt. Das ergibt keinen Unterschied (außer dass es clean-code-technisch unschöner wurde). Das Problem blieb unverändert: Die deleteItem-Methode wird in ner Lines-abhängigen For-Schleife ausgeführt. Nämlich in der ReadDoc-Sub => Daher darfst Du derzeit deleteItem gar nicht ausführen, da dort Items von Lines gelöscht werden, d.h. Du darfst in Deiner ReadDoc während der For-Schleife nicht deleteItem ausführen. Merk Dir stattdessen das zu löschende Item z.B. in einer List(Of)) und übergib deleteItem nach der ReadDoc-for-Schleife jene Liste. Das führt dann natürlich dazu, dass der Name "deleteItem" dann sinnigerweise angepasst werden sollte.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „VaporiZed“ ()

    Ich finds echt Schade, dass es keinen ReverseEnumerator gibt, der von bestimmten Sachen implementiert wird(gerade Dinge mit fester sortierter größe können das, da kann dann gut optimiert werden kann).
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---
    Will aber etwas Grundimplementiert haben, das mir nicht den Heap mit allocs vollhaut und auch nicht jedesmal die relative Adresse berechnen muss(so wie beim normalen List-foreach halt auch - passiert bei sonstigen Enumeratoren auch nicht).
    Es fehlt allgemein voll viel Zeug was C# zur Compiletime optimieren könnte, wenigstens für Release.
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---