使用'ReplaceWith'迭代XElement集合只有在我首先使用'ToList()'时才有效

时间:2012-10-24 12:18:57

标签: c# linq-to-xml iteration

此代码有效:

var element = XElement.Parse("<div><span><em>Content</em></span><span><em>Content2</em></span></div>");

var spans = element.Descendants("span").ToList();

foreach(var span in spans)
{
    span.ReplaceWith(span.Nodes());
}

这不会,错误&#39;对象引用未设置为对象的实例。&#39;:

var element = XElement.Parse("<div><span><em>Content</em></span><span><em>Content2</em></span></div>");

var spans = element.Descendants("span");

foreach(var span in spans)
{
    span.ReplaceWith(span.Nodes());
}

唯一的区别是我删除了&#39; ToList()&#39;在创建后代节点列表时。这是为什么?

IQueryable实现IEnumerable,我想迭代强制延迟执行,为什么&#39; ToList()&#39;在这里有所作为?

1 个答案:

答案 0 :(得分:4)

在第二种情况下,当你迭代它时,你正在改变集合spans,所以发生了不好的事情。也许它试图告诉你它记得的下一个span,但你已经删除了它。

(在列表等核心集合中,您会收到一个明确说明集合已被修改的异常。例如,在List<.>中,每次修改列表时都会更改版本号;当您调用时列表枚举器上的ToNext,如果版本已更改,则抛出异常。

在LINQ-to-XML中,开发人员似乎没有添加这种行为。)

在第一种情况下,修改原始树时不会修改ToList创建的列表。

我会尝试这样的事情:

XElement span = null; // or whatever class this should be
while ((span = element.Descendants("span").FirstOrDefault()) != null)
    span.ReplaceWith(span.Nodes());

即。一个接一个地替换跨度,而不是试图一次性取出它们然后替换它们。