【问题标题】:XmlNode.ParentNode.RemoveChild stops foreachXmlNode.ParentNode.RemoveChild 停止 foreach
【发布时间】:2015-11-12 03:48:00
【问题描述】:

我正在尝试删除类型为“可删除”的每个注释,但在它达到 1 个可删除后,foreach 停止。在这种情况下,只通过 test2.exe 和 test.exe。

这是我的 XML 文件的样子:

<folder name="bin">
    <file name="test2.exe" type="undeletable">test</file>
    <file name="test.exe" type="deletable">test</file>
    <file name="test1.exe" type="deletable">test</file>
    <file name="kernel.sys" type="undeletable">test</file>
</folder>

这是 C#:

XmlNodeList fileNodeLIst = fileNode.SelectNodes("file");
foreach(XmlNode file in fileNodeLIst) {
    if (file.Attributes["type"].Value == "undeletable") {
        TerminalSystemAddMessage("Error: Unable to delete " + file.Attributes["name"].Value);
    } else if (file.Attributes["type"].Value == "deletable") {
        file.ParentNode.RemoveChild(file);
        TerminalSystemAddMessage("Deleted: " + file.Attributes["name"].Value);
    }
}

我做错了吗? 为什么 foreach 循环会中断,我该如何解决?

【问题讨论】:

  • 修改你的代码以便我可以实际运行它,我发现它工作得很好。请提供可靠地重现问题的a good, minimal, complete code example
  • 我发布的内容运行不正常。当可删除对象通过时,它会停止 foreach。
  • 我不怀疑在您的场景中它无法运行。否则你不会发布这个问题。但是您没有提供 任何其他人 可以不加修改地运行的代码示例。没有它,你的代码有什么问题就不清楚了。我在不修改您发布的代码的情况下复制/粘贴,但当然必须添加其他代码才能让任何东西运行。当我这样做时,结果很好。请阅读并理解我提供的链接,以便您知道需要什么样的代码示例。

标签: c# xml foreach


【解决方案1】:

使用“for”迭代语句代替“foreach”迭代语句,如下所示:

  XmlNodeList fileNodeLIst = fileNode.SelectNodes("file");
    for(int iNode = fileNodeList.Count - 1; iNode >= 0; iNode --)
      {
        XmlNode file = fileNodeLIst[iNode];
        if(file.Attributes["type"].Value == "undeletable"){
            TerminalSystemAddMessage("Error: Unable to delete " + file.Attributes["name"].Value);
        }else if(file.Attributes["type"].Value == "deletable"){
            file.ParentNode.RemoveChild(file);
            TerminalSystemAddMessage("Deleted: " + file.Attributes["name"].Value);
        }
      }

foreach 语句为实现 System.Collections.IEnumerable 或 System.Collections.Generic.IEnumerable 接口的数组或对象集合中的每个元素重复一组嵌入语句。 foreach 语句用于遍历集合以获取您想要的信息,但不能用于在源集合中添加或删除项目以避免不可预知的副作用。如果您需要在源集合中添加或删除项目,请使用 for 循环。 来源:https://msdn.microsoft.com/en-us/library/ttw7t8t6.aspx

【讨论】:

  • 首先,SelectNodes() 返回的集合并不是真正的 DOM 集合。所以可以在foreach中修改DOM集合就好了。其次,请不要使用“sn-ps”发布C#代码。只需发布代码。
  • 注意:节点列表从最后一个遍历到第一个。
  • @Peter Duniho,感谢您的来信。 StackOverflow 上怎么没有 c# sn-p 支持?
  • @TeunissenStefan,如果有帮助,请标记我的回答。谢谢。
  • “为什么 StackOverflow 上没有 c# sn-p 支持?” -- 同样的原因也没有对其他语言的 sn-p 支持:大多数人都没有实现它可能是因为这样做并不实际。 Web 代码是一回事——你可以保证呈现在浏览器上下文中——但任意 C#、Java、C++、Pascal、Python、Perl、Ada 等都无法全面处理。
【解决方案2】:

您可能会发现这种方法更简洁:

var messages =
(
    from file in fileNode.SelectNodes("file").Cast<XmlNode>()
    let deletable = file.Attributes["type"].Value == "deletable"
    let name = file.Attributes["name"].Value
    select String.Format(
        deletable
            ? "Deleted: {0}"
            : "Error: Unable to delete {0}",
        name)
).ToList();

var deletables =
(
    from file in fileNode.SelectNodes("file").Cast<XmlNode>()
    where file.Attributes["type"].Value == "deletable"
    select file
).ToList();

deletables.ForEach(file => file.ParentNode.RemoveChild(file));
messages.ForEach(message => TerminalSystemAddMessage(message));

这将删除节点与遍历列表分开 - 从而停止您遇到的问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-09-09
    • 2015-04-21
    • 2016-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-27
    相关资源
    最近更新 更多