为什么我的 C# Xml 代码仅在我枚举可枚举变量时有效
Why does my C# Xml code only work when I enumerate variable enumerable
我正在编写格式化 XML 文件的代码,以便子文件夹节点实际上嵌套在它们的父节点中。源 XML 将每个文件夹作为根中的一个单独的子节点,而不是像您期望的那样在其主文件夹中包含子文件夹的正确树。这个问题是关于这段代码的:
// Load original XML
string sFile = "PathFile";
XmlDocument doc = new XmlDocument();
doc.Load(sFile);
var n = doc.DocumentElement.SelectNodes ("//*"); // Load all nodes into nodelist n
// int nCount = n.Count; // If uncommented code works
foreach(XmlNode x in n)
{ rest of the code }
现在我的代码可以正常工作,但只是有时,即使在 运行 之间没有更改任何内容。我已将其缩小为:当调试 Visual Studio 中的代码时,如果我只是从头到尾 运行 代码,就会出错。如果我中途中断并查看 XmlNodelist n 中的属性(通过将光标悬停在它上面并查看元素计数)它确实有效。 发现这一点后,我添加了
int nCount = n.Count;
行,现在代码在 运行ning 从头到尾无人监督时有效。
这是怎么回事?解决这个问题的正确方法是什么?注意:doc.LoadXml 不适用于此特定文件。
谢谢大家,
托马斯
简短的回答:因为 XmlNodeList
.
XmlNode.SelectNodes()
returns 一个 XmlNodeList
(从技术上讲,一个 XPathNodeList
),它是匹配选择的节点的 "live list"(在此例如 XPath 选择)。
当您迭代 XPathNodeList
或以其他方式访问它时,它会通过匹配节点,根据需要构建内部列表,并根据需要 returning 它们。
因此,如果您在遍历节点时尝试重新排列文档,这可能会扰乱迭代并导致它在您遍历所有节点之前停止。当文档在其下方移动时,迭代基本上是在追逐一个移动的目标。
然而,为了 return Count
属性 的值,XPathNodeList
基本上需要找到每个匹配的节点并计算它们,所以它遍历整个匹配集并将它们全部放入内部列表中。
public override int Count {
get {
if (! done) {
ReadUntil(Int32.MaxValue);
}
return list.Count;
}
}
我认为这可以解释您所看到的情况。当您在进行更改之前访问 Count
属性 时,它会构建整个节点列表,作为副作用,因此当您实际遍历它们时仍然会填充该列表。
当然,依赖这种未记录的行为是不明智的。
相反,我建议您实际将 XmlNodeList
的内容复制到您自己的列表中,然后遍历该列表:
string sFile = "PathFile";
XmlDocument doc = new XmlDocument();
doc.Load(sFile);
var allNodes = doc.DocumentElement
.SelectNodes("//*")
.OfType<XmlNode>() // using System.Linq;
.ToList();
foreach (XmlNode x in allNodes)
{
// rest of the code
}