我很惊讶地看到以下代码中的所有元素都没有被迭代:
IEnumerable<XElement> dataStorageGroupElements = document.Descendants().Where(x => "Xms.Common.DataStorageGroup" == (string)x.Attribute("NodeType"));
int counter = 0;
foreach (XElement dataStorageGroupElement in dataStorageGroupElements)
{
Console.WriteLine($"Counter={counter++}, NbElements={dataStorageGroupElements.Count()}");
XElement newParent = GetNewParentForDataStorageGroup(dataStorageGroupElement);
dataStorageGroupElement.Remove();
newParent.Add(dataStorageGroupElement);
}
输出是:
Counter=0, NbElements=12
Counter=1, NbElements=12
Counter=2, NbElements=12
Counter=3, NbElements=12
Counter=4, NbElements=12
Counter=5, NbElements=12
Counter=6, NbElements=12
使用ToArray()更改代码以执行枚举可以解决此问题:
IEnumerable<XElement> dataStorageGroupElements = document.Descendants().Where(x => "Xms.Common.DataStorageGroup" == (string)x.Attribute("NodeType")).ToArray();
使用上面的代码,计数器将递增到11。
为什么要跳过某些元素here。但为什么NbElements总是12?它只是第一次评估吗?
答案 0 :(得分:3)
MSDN中描述了该问题:"Mixed declarative code / imperative code bugs (LINQ to XML)":
LINQ to XML包含允许您直接修改XML树的各种方法。您可以添加元素,删除元素,更改元素的内容,添加属性等。修改XML树(LINQ to XML)(C#)中描述了此编程接口。如果您正在迭代其中一个轴(例如Elements),并且在迭代轴时修改XML树,则最终会出现一些奇怪的错误。
这个问题有时被称为“万圣节问题”。
基本上,在你懒洋洋地迭代它时修改一些东西是个坏主意。在开始修改内容之前使用ToArray
来实现查询的方法是正确的,尽管我个人使用ToList
代替ToArray
。