Consider the following code:
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();
}
}
}
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:
Why do I not get an invalid operation exception?
Note that the equivilent code in IDEOne.com does give the expected exception: http://ideone.com/qoRBbb
Also note that if i remove all the LINQ (.Cast().Where()
) I get the same result, only one node removed, no exception.
Is there some issue with my settings in VSExpress?
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.
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).
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".
Console.WriteLine("Removing:");
in your result either. Are you sure the loop fires at all? – Pelagian