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

Cri*_*scu 4 c# xml linq linq-to-xml

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

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

var rdr = XmlReader.Create("path/to/huge_3Gb.xml");
Run Code Online (Sandbox Code Playgroud)

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

文件XDocument.Load(),确实,它使用状态XmlReader.Create().

我想,就像Linq一样,我会得到Linq2Xml的延迟执行行为.
但后来我尝试了这个,就像我通常做的任何涉及文件的事情:

using(var xdoc = XDocument.Load("file")){ ... }
Run Code Online (Sandbox Code Playgroud)

而且惊喜!它没有编译,因为XDocument没有实现IDisposable!

嗯,这很特别!我将如何不断释放文件句柄时,我使用的完成XDocument

然后我XDocument.Load()突然意识到:可能会立刻吃掉内存中的整个Xml(并立即关闭文件句柄)?

所以我尝试过:

var xdoc = XDocument.Load("path/to/huge_3Gb.xml");
Run Code Online (Sandbox Code Playgroud)

等待,等待,然后过程说:

Unhandled Exception: OutOfMemoryException.
Run Code Online (Sandbox Code Playgroud)

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

</rant>

我的问题是:

  1. 我错过了什么,有一种方法可以懒惰地使用Linq到Xml吗?

  2. 如果上一个问题的答案是"否":

是否存在客观原因,为什么Linq to Xml API不能具有类似于Linq to Objects的延迟行为?在我看来,至少有一些操作(例如,只有前向可能的事情XmlReader)可以懒得实现.

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

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

Ser*_*kiy 6

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

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

<movies>
  <movie id="1" name="Avatar"/>
  <movie id="2" name="Doctor Who"/>
</movies>
Run Code Online (Sandbox Code Playgroud)

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

 var xdoc = XDocument.Parse(xml_string);
 // or XDocument.Load(file_name);
 // or new XDocument(new XElement("movies"), ...)
Run Code Online (Sandbox Code Playgroud)

现在定义查询:

var query = xdoc.Descendants("movie");
Run Code Online (Sandbox Code Playgroud)

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

xdoc.Root.Add(new XElement("movie"), new XAttribute("id", 3));
Run Code Online (Sandbox Code Playgroud)

现在执行查询:

int moviesCount = query.Count(); // returns 3
Run Code Online (Sandbox Code Playgroud)

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

注意:XDocument不实现IDisposable,因为它在构造节点图之后不保存任何非托管资源.