返回IEnumerable <t>时,为什么XmlReader会关闭?

时间:2016-04-28 17:25:12

标签: c# .net xmlreader yield-return

我有以下扩展方法:

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()没有做任何事情),运行代码会导致无限循环,但是当我更改以下行时:< / p>

return reader.GetElement(elementName));

为:

foreach (var xElement in reader.GetElement(elementName, ignoreCase))
{
    yield return xElement;
}
一切似乎都运转良好。为什么前一个实现会导致读者关闭?

1 个答案:

答案 0 :(得分:1)

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

当您将其封装在foreach循环中时,关闭阅读器的using语句的效果会延迟到foreach终止,到那时为止#39} ;没关系,到那时你不再需要读者了。