Linq, XmlNodes, foreach's und Ausnahmen

9

Betrachten Sie den folgenden Code:

%Vor%

Wenn ich diesen Code in visual studio express 2010 ausfühle, erhalte ich wie erwartet keine Ausnahme. Ich würde eine davon erwarten, weil ich während der Iteration etwas aus einer Liste entferne.

Was ich bekomme ist eine Liste zurück mit nur dem ersten Kind Knoten entfernt:

Warum bekomme ich keine Ausnahme für ungültige Operationen?

Beachten Sie, dass der Äquivalenzcode in IDEOne.com die erwartete Ausnahme enthält: Ссылка

Beachten Sie auch, dass wenn ich alle LINQ ( .Cast().Where() ) lösche, das gleiche Ergebnis, nur ein Knoten entfernt, keine Ausnahme.

Gibt es ein Problem mit meinen Einstellungen in VSExpress?

Beachten Sie, dass ich weiß, dass die verzögerte Ausführung involviert ist, aber ich würde erwarten, dass die where-Klausel bei der Iteration auf die Quellenaufzählung (Kind-Notiz) die erwartete Ausnahme ergibt.

Mein Problem ist, dass ich diese Ausnahme in VSexpress nicht bekomme, aber in IDEOne (ich würde es in beiden Fällen erwarten, oder zumindest wenn nicht, würde ich das korrekte Ergebnis erwarten).

Aus Woutters Antwort scheint es, dass es den Iterator ungültig macht, wenn das erste Kind entfernt wird, anstatt eine Ausnahme zu geben. Gibt es etwas Offizielles, das das sagt? Ist dieses Verhalten in anderen Fällen zu erwarten? Ich würde den Iterator stillschweigend als ungültig erklären, anstatt mit einer Ausnahme "Leise, aber tödlich".

    
George Duckett 28.03.2013, 13:05
quelle

2 Antworten

2

Auch der folgende Code wird keine Ausnahmen auslösen:

%Vor%

Und es wird genau ein Element entfernen. Ich bin nicht 100%, dass meine Erklärung richtig ist, aber es ist auf dem richtigen Weg. Wenn Sie über eine Sammlung iterieren, rufen Sie ihren Enumerator ab. Für XmlNode, eine Sammlung, ist dies eine benutzerdefinierte Klasse namens XmlChildEnumerator .

Wenn Sie die MoveNext-Implementierung über Reflector nachschlagen würden, würden Sie sehen, dass der Enumerator sich an den Knoten erinnert, den er gerade betrachtet. Wenn Sie MoveNext aufrufen, wechseln Sie zum nächsten Geschwister.

Was im obigen Code passiert, ist, dass Sie den ersten Knoten aus der Sammlung erhalten. Der im Körper der foreach-Schleife implizit erzeugte Enumerator verwendet diesen ersten Knoten als seinen aktuellen Knoten. Dann entfernen Sie im Körper der foreach-Schleife diesen Knoten.

Nun wird dieser Knoten von der Liste entfernt und die Ausführung wird erneut auf MoveNext aufgerufen. Da wir jedoch gerade den ersten Knoten aus der Sammlung entfernt haben, wird er aus der Sammlung entfernt, und der Knoten hat keine Geschwister. Da für den Knoten kein Geschwister vorhanden ist, wird die Iteration angehalten und foreach-Schleife beendet, wodurch nur ein einzelnes Element entfernt wird.

Dies löst keine Ausnahme aus, da nicht überprüft wird, ob die Sammlung geändert wurde, sondern nur zum nächsten Knoten, der gefunden werden kann. Da der entfernte Knoten jedoch nicht zu einer Sammlung gehört, wird die Schleife angehalten.

Hoffe, das klärt das Problem auf.

    
Toni Petrina 28.03.2013, 13:55
quelle
2

Da Sie über ChildNodes iterieren, wird durch das Entfernen des ersten untergeordneten Elements der Iterator ungültig. Aus diesem Grund stoppt die Iteration nach dem ersten Entfernen.

Wenn Sie Ihre Filterung und Iteration aufteilen, wird Ihr Code alle Elemente entfernen:

%Vor%     
Wouter de Kort 28.03.2013 13:12
quelle