Linq to Xml:XDocument是一个缓存读者吗?

时间:2013-10-18 10:59:06

标签: c# xml linq linq-to-xml

我喜欢Linq to Xml API。我用过的最简单的一个。

我还记得它是在XmlReader上面实现的,这是一个非缓存读者,意思是:

var rdr = XmlReader.Create("path/to/huge_3Gb.xml");

...会立即返回(最多可能读取xml标题)。

XDocument.Load() documentation表示确实使用了XmlReader.Create()

我希望,与所有 Linq 一样,我会得到Linq2Xml的延迟执行行为。
但后来我尝试了这个,就像我通常做的那样触及文件:

using(var xdoc = XDocument.Load("file")){ ... }
和惊喜!它没有编译,因为XDocument没有实现IDisposable

嗯,那太奇特了!当我使用XDocument时,我将如何永远释放文件句柄?

然后我突然意识到:也许XDocument.Load()立即在内存中占用整个Xml(并立即关闭文件句柄)?

所以我试过了:

var xdoc = XDocument.Load("path/to/huge_3Gb.xml");
等等,等待,然后过程说:

Unhandled Exception: OutOfMemoryException.

所以Linq to Xml接近完美(令人敬畏的API),但没有雪茄(在大型Xmls上使用时)。

</rant>

我的问题是:

  1. 我是否遗漏了某些内容,并且有一种方法可以懒惰地使用Linq到Xml?

  2. 如果上一个问题的答案为“否”:

  3. 为什么Linq to Xml API不能具有类似于Linq to Objects的延迟行为?在我看来,至少有一些操作(例如只有前向XmlReader可能的事情)可以懒惰地实现。

    ...或者它没有像这样实现,引用Eric Lippert

      

    “因为没有人设计,指定,实施,测试,   记录并发送该功能“?

1 个答案:

答案 0 :(得分:6)

实际上Linq to Xml使用延迟执行。但它查询内存数据,而不是文件中的数据。您可以手动从文件,流,字符串或构建文档加载数据 - 无论内存节点图如何构建都无关紧要。 Linq to xml用于查询xml树的内存中表示(即对象图)。

这是一个示例,显示延迟执行如何与Linq一起使用到Xml。考虑您有XDocument,其中包含具有以下数据的对象图:

<movies>
  <movie id="1" name="Avatar"/>
  <movie id="2" name="Doctor Who"/>
</movies>

如何创建此xml数据的内存表示并不重要。 E.g。

 var xdoc = XDocument.Parse(xml_string);
 // or XDocument.Load(file_name);
 // or new XDocument(new XElement("movies"), ...)

现在定义查询:

var query = xdoc.Descendants("movie");

您可以修改内存中的xml表示,该文档包含:

xdoc.Root.Add(new XElement("movie"), new XAttribute("id", 3));

现在执行查询:

int moviesCount = query.Count(); // returns 3

正如您所看到的,Linq to Xml使用延迟执行,但它的工作方式类似于Linq to Objects - 此处查询内存数据。

注意:XDocument没有实现IDisposable,因为在构造节点图之后它不包含任何非托管资源。