2016-04-28 60 views
0

我有以下的扩展方法:为什么在返回IEnumerable <T>时XmlReader会关闭?

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)); 
    } 
} 

然后我尝试使用在XML文件打开FileStream,并得到一个特定的元素:

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); 
} 

但是运行代码产生一个无限循环由于xml读取器正在关闭(reader.EOFfalsereader.Read()没有做任何事情),但是当我更改以下行时:

return reader.GetElement(elementName)); 

到:

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

一切似乎是工作的罚款。为什么前面的实施导致读者关闭?

+0

我一直检查'reader.Read()'的返回值来找到文件的结尾,但我不知道它是否应该“更可靠”(我从来没有检查过EOF '物业tbh)。 –

+0

这将是一个合乎逻辑的事情,但在这种情况下,我不能因为:http://stackoverflow.com/questions/36909789/why-is-the-xmlreader-skipping-elements – babayi

+0

你可以使用'do {.. 。}而reader.Read();'而不是,如果你想。 –

回答

1

reader.GetElement(elementName)尚未开始枚举。它返回一个对象,一旦你看到它包含的内容,就从reader开始读取。由于您直接返回该对象,并且return语句被包装在using中,因此using语句会导致读者在枚举开始之前关闭。

当你把它包装在一个foreach循环,关闭读者using语句的作用被延迟,直到foreach终止,到那个时候它会好起来的,到那个时候,你不再需要读卡器。

相关问题