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