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>
我的问题是:
我错过了什么,有一种方法可以懒惰地使用Linq到Xml吗?
如果上一个问题的答案是"否":
是否存在客观原因,为什么Linq to Xml API不能具有类似于Linq to Objects的延迟行为?在我看来,至少有一些操作(例如,只有前向可能的事情XmlReader)可以懒得实现.
......或者它没有像这样实现,引用Eric Lippert,
"因为没有人设计,指定,实施,测试,记录和发送该功能"?
实际上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,因为它在构造节点图之后不保存任何非托管资源.