使用 linq2xml 遍历 ienumerable

iterating over ienumerable with linq2xml

我很惊讶地发现并没有迭代以下代码中的所有元素:

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。

描述了为什么跳过某些元素 。但为什么 NbElements 总是 12?是第一次评价吗?

MSDN 中描述了该问题:"Mixed declarative code / imperative code bugs (LINQ to XML)":

LINQ to XML contains various methods that allow you to modify an XML tree directly. You can add elements, delete elements, change the contents of an element, add attributes, and so on. This programming interface is described in Modifying XML Trees (LINQ to XML) (C#). If you are iterating through one of the axes, such as Elements, and you are modifying the XML tree as you iterate through the axis, you can end up with some strange bugs.

This problem is sometimes known as "The Halloween Problem".

基本上,在您懒惰地迭代某些内容时对其进行修改是个坏主意。在开始修改之前使用 ToArray 实现查询的方法是正确的,尽管我个人使用 ToList 而不是 ToArray