LINQ中,将XMLNode,的foreach的和异常 [英] Linq, XmlNodes, foreach's and exceptions

查看:195
本文介绍了LINQ中,将XMLNode,的foreach的和异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑下面的代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using System.Xml.Linq;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            XmlDocument xmlDoc = new XmlDocument();

            xmlDoc.LoadXml(@"<Parts>
  <Part name=""DisappearsOk"" disabled=""true""></Part>
  <Part name=""KeepMe"" disabled=""false""></Part>
  <Part name=""KeepMe2"" ></Part>
  <Part name=""ShouldBeGone"" disabled=""true""></Part>  
</Parts>");

            XmlNode root = xmlDoc.DocumentElement;
            List<XmlNode> disabledNodes = new List<XmlNode>();

            try
            {

                foreach (XmlNode node in root.ChildNodes.Cast<XmlNode>()
                                             .Where(child => child.Attributes["disabled"] != null &&
                                                             Convert.ToBoolean(child.Attributes["disabled"].Value)))
                {
                    Console.WriteLine("Removing:");
                    Console.WriteLine(XDocument.Parse(node.OuterXml).ToString());
                    root.RemoveChild(node);
                }
            }
            catch (Exception Ex)
            {
                Console.WriteLine("Exception, as expected");
            }

            Console.WriteLine();
            Console.WriteLine(XDocument.Parse(root.OuterXml).ToString());

            Console.ReadKey();
        }
    }
}

当我运行这段代码 Visual Studio速成2010 我没有得到一个异常,符合市场预期。 。我期望一个,因为我是从列表中删除的东西,而它的迭代

When I run this code in visual studio express 2010 I don't get an exception, as expected. I'd expect one because I'm removing something from a list while iterating it.

我做什么得到的是一个列表,只有删除的第一个子节点:

What I do get is a list back with only the first child node removed:

为什么我没有得到一个无效操作异常?

注意equivilent代码IDEOne.com确实给预期的异常 http://ideone.com/qoRBbb

还要注意的是,如果我删除所有LINQ( .Cast()。其中​​())我得到的同样的结果,只有一个节点删除,也不例外。

Also note that if i remove all the LINQ (.Cast().Where()) I get the same result, only one node removed, no exception.

有一些问题,我在VSExpress设置?

Is there some issue with my settings in VSExpress?

请注意,我知道延迟执行涉及,但是我希望在where子句,当迭代后依照来源枚举迭代(子注),这将给我预期的异常。

Note that I know deferred execution is involved, but I'd expect the where clause, when iterated upon to iterate upon the source enumeration (child note), which would give the exception I'm expecting.

我的问题是,我不明白在VSexpress该异常,但在IDEOne做(我希望它在两个/所有的情况下,或至少如果不是,我期望正确的结果)。

My issue is that I don't get that exception in VSexpress, but do in IDEOne (I'd expect it in both/all cases, or at least if not, I'd expect the correct result).

从的Wouter's回答似乎当第一个孩子被移除它的无效迭代器,而不是让一个例外。有什么正式的说,这?是在其他情况下,可以预料这种行为?我会打电话迭代器有一个例外默默无效,而不是沉默的,但致命的。

From Wouter's answer it seems it's invalidating the iterator when the first child is removed, rather than giving an exception. Is there anything official that says this? Is this behaviour to be expected in other cases? I'd call invalidating the iterator silently rather than with an exception "Silent but deadly".

推荐答案

即使下面的代码获得了 ŧ抛出任何异常:

Even the following code won't throw any exceptions:

foreach (XmlNode node in root.ChildNodes)
    root.RemoveChild(node);

和它会删除只有一个元素。我不是100%,我的解释是正确的,但它是在正确的轨道上。当您遍历集合,您检索其枚举。对于XmlNode的,这是一个集合,这是 XmlChildEnumerator 调用自定义的类。

And it will remove exactly one element. I am not 100% that my explanation is correct, but it is on the right track. When you iterate over a collection, you retrieve its enumerator. For XmlNode, which is a collection, this is a custom class called XmlChildEnumerator.

如果你想查找通过反射MoveNext的实现,你会看到枚举记得它目前正在研究的节点。当你调用的MoveNext,移动到下一个兄弟。

If you would look up the MoveNext implementation via Reflector, you would see that the enumerator remembers the node it is currently looking at. When you call MoveNext, you move onto the next sibling.

会发生什么事在上面的代码是你从集合中第一个节点。在foreach循环体隐式生成枚举采取了第一个节点作为当前节点。然后,在foreach循环的身体,在删除节点。

What happens in the code above is that you get the first node from the collection. Enumerator implicitly generated in the body of the foreach loop takes that first node as its current node. Then, in the body of the foreach loop you remove that node.

现在的节点从列表和执行移动到再次调用MoveNext的分离。然而,由于我们刚才除去从集合中第一个节点时,它被从收集分离的和节点没有兄弟。由于没有兄弟为节点,迭代停止,foreach循环退出,从而消除只有一个元素。

Now that node is detached from the list and the execution moves onto calling MoveNext again. However, since we have just removed the first node from the collection, it is detached from the collection and node has no sibling. Since there is no sibling for the node, iteration stops and foreach loop exits, thus removing only single element.

因为这不会引发异常不检查收藏已经改变,它只是想移动到它能否找到下一个节点。但由于去除(分离)节点不属于集合,循环停止。

This doesn't throw exception since it doesn't check if the collection has been changed, it just wants to move on to the next node it can find. But since the removed (detached) node doesn't belong to a collection, the loop stops.

希望这清除了问题。

这篇关于LINQ中,将XMLNode,的foreach的和异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆