【问题标题】:Why is the XmlReader getting closed when returning an IEnumerable<T>?为什么返回 IEnumerable<T> 时 XmlReader 会关闭?
【发布时间】:2016-08-23 14:58:07
【问题描述】:

我有以下扩展方法:

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

然后我尝试打开 FileStream 并使用以下方法在 XML 文件中获取特定元素:

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

一切似乎都运行良好。为什么以前的实现会导致阅读器关闭?

【问题讨论】:

  • 我一直检查reader.Read()的返回值来查找文件的结尾,但我不知道它是否应该“更可靠”(我从来没有检查过EOF 属性tbh)。
  • 这将是一个合乎逻辑的事情,但在这种情况下我不能因为:stackoverflow.com/questions/36909789/…
  • 如果你愿意,你可以改用do { ... } while reader.Read();

标签: c# .net xmlreader yield-return


【解决方案1】:

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

当您将其包装在 foreach 循环中时,using 语句关闭阅读器的效果会延迟到 foreach 终止,到那时一切都会好起来的,到那时您不再需要读者。

【讨论】:

    猜你喜欢
    • 2011-07-29
    • 1970-01-01
    • 2014-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多