1

此代码有效:

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());
}

这不会,给出错误“对象引用未设置为对象的实例。”:

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());
}

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

IQueryable 实现了 IEnumerable,我认为迭代强制延迟执行,那么为什么 'ToList()' 在这里有所作为呢?

4

1 回答 1

4

在第二种情况下,您spans在迭代集合时正在更改集合,所以会发生不好的事情。也许它试图给你它所记得的 next span,但你已经删除了它。

(在诸如列表之类的核心集合中,您会得到一个明确说明该集合已被修改的异常。例如,在 aList<.>中,每次修改列表时都会更改版本号;当您调用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());

即一个接一个地替换跨度,而不是试图一口气将它们全部替换然后替换它们。

于 2012-10-24T12:30:24.907 回答