2016-04-28 20 views
0

Ich habe folgende Erweiterungsmethoden: mitWarum wird der XmlReader geschlossen, wenn ein IEnumerable <T> zurückgegeben wird?

public static IEnumerable<XElement> GetElement(this XmlReader reader, string elementName) 
{  
    reader.MoveToElement(); 

    while (!reader.EOF) 
    { 
     if (reader.NodeType == XmlNodeType.Element 
      && reader.Name.Equals(elementName)) 
     { 
      yield return XNode.ReadFrom(reader) as XElement; 
     } 

     reader.Read(); 
    } 
} 

public static IEnumerable<XElement> ExtractElement(this Stream stream, string elementName) 
{  
    using (var reader = XmlReader.Create(stream)) 
    { 
     return reader.GetElement(elementName)); 
    } 
} 

ich dann versuchen, ein FileStream zu öffnen und ein bestimmtes Element in einer XML Datei erhalten:

using (var stream = File.Open("My.xml", FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) 
{ 
    var element = stream.ExtractElement("subscriptionForms").First(); 
    element.Elements("subscriptionForm").Count().ShouldBe(11); 
} 

jedoch die Code-Ergebnisse in einer Endlosschleife läuft aufgrund der XML-Leser geschlossen (reader.EOF wird false und reader.Read() nichts tun), aber wenn ich die folgende Zeile ändern:

return reader.GetElement(elementName)); 

zu:

foreach (var xElement in reader.GetElement(elementName, ignoreCase)) 
{ 
    yield return xElement; 
} 

alles scheint gut zu funktionieren. Warum veranlasst die frühere Implementierung den Leser zu schließen?

+0

Ich habe immer den Rückgabewert von 'reader.Read()' überprüft, um das Ende der Datei zu finden, aber ich weiß nicht, ob __should_ "zuverlässiger" sein sollte (Ich habe nie die 'EOF überprüft 'Eigenschaft tbh). –

+0

Das wäre eine logische Sache zu tun, aber in diesem Fall kann ich nicht wegen: http://stackoverflow.com/questions/36909789/why-is-the-xmlreader-skipping-elements – babayi

+0

Sie könnten 'tun {.. .} während reader.Read(); 'stattdessen, wenn Sie möchten. –

Antwort

1

reader.GetElement(elementName) beginnt noch nicht mit dem Aufzählen. Es gibt ein Objekt zurück, das nach dem Betrachten dessen, was es enthält, beginnt, von reader zu lesen. Da Sie das Objekt direkt zurückgeben und die Anweisung return in eine using eingeschlossen ist, bewirkt die Anweisung using, dass der Leser geschlossen wird, bevor die Aufzählung beginnt.

Wenn Sie es in einer Schleife foreach wickeln, die Wirkung der using Aussage wird den Leser schließen, bis die foreach endet verzögert, und von dieser Zeit wird es in Ordnung sein, von dieser Zeit müssen Sie nicht mehr die Leser.