简体   繁体   English

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

[英]Iterating over an XElement collection using 'ReplaceWith' only works if I use 'ToList()' first

This code works: 此代码有效:

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

This does not, giving the error 'Object reference not set to an instance of an object.': 这不会,给出错误'对象引用未设置为对象的实例。':

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

The only difference is I have removed the 'ToList()' when creating the list of Descendant Nodes. 唯一的区别是我在创建后代节点列表时删除了'ToList()'。 Why is this? 为什么是这样?

IQueryable implements IEnumerable, and I thought iterating forced deferred execution, so why is 'ToList()' making a difference here? IQueryable实现IEnumerable,我想迭代强制延迟执行,那么为什么'ToList()'在这里有所作为呢?

In the second case, you're changing the collection spans while you're iterating over it, so bad things happen. 在第二种情况下,当你迭代它时,你正在改变收集spans ,所以发生了不好的事情。 Maybe it's trying to give you what it remembers to be the next span , but you've already removed it. 也许它试图给你它记得的下一个span ,但你已经删除了它。

(In core collections like lists, you get an exception explicitly stating that the collection has been modified. For example, in a List<.> , there's a version number that changes every time the list is modified; when you call ToNext on a list enumerator, if the version has changed, an exception is thrown. (在列表等核心集合中,您会明确指出集合已被修改。例如,在List<.> ,每次修改列表时都会更改版本号;当您在列表上调用ToNext时枚举器,如果版本已更改,则抛出异常。

In LINQ-to-XML it appears that the developers didn't add this kind of behaviour.) 在LINQ-to-XML中,开发人员似乎没有添加这种行为。)

In the first case, the list created by ToList isn't modified when you modify the original tree. 在第一种情况下,修改原始树时不会修改由ToList创建的列表。

I'd try something like this: 我会尝试这样的事情:

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

ie replace the spans one by one, rather than trying to get them all in one go and then replace them. 即逐个替换跨度,而不是试图一次性取出它们然后更换它们。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM