LINQ To Xml:迭代中的万圣节问题
2011-04-19 16:11
78 查看
最近在研究操作xml的最好方式,随便看了几个英文版电子书,上面都提到DOM 和 linq to xml方式的比较
linq to xml的方法,简洁直观,代码量小,下面扯扯本文想要说的万圣节问题,这个词从以下书中来
Pro LINQ: Language Integrated Query in C# 2010
第231页,(Halloween Problem)
那么什么是万圣节问题呢,不说名字怎么来了,书里解释了一下。下面说一下,具体指的是什么
万圣节问题指在迭代一组元素的时候,删除或改变元素个数时,迭代出现的的不正常行为,但这种问题可以避免,同时达到本来要达到的效果
书中的例子
理论上在foreach的时候,每次都调用remove了,所以每次都应该打印出删除的元素,并且父元素下的子
元素应该全部都删除掉了,可是打印出的结果并非如此
竟然还剩一个元素没有删除掉!并且也只打印出第一个元素删除掉的那句话。
费解吗?其实linq的执行都是延迟执行的,这是其导致的潜在副作用
书中给出的解决方案是,缓存元素序列,其中用到了 ToArray 操作符
注意LINQ To XML 构建XML树的时候是延迟查询,也就是Console.WriteLine(xDocument); 这句才真正生成XML树,故之前的循环如果不缓存起来,是不可能操作到XML树的
注意这句 XElement element in elements.ToArray()
ToArray在MSDN文档中
http://msdn.microsoft.com/zh-cn/library/bb298736.aspx
有这么一句话
ToArray<TSource>(IEnumerable<TSource>) 方法强制进行直接查询计算,并返回一个包含查询结果的数组。 可将此方法追加到您的查询,以获得查询结果的缓存副本。
接着打印结果变成我们最终想要的那样
如此这般,问题就解决了
我终于也明白为什么之前我在forearch datarow in datatable.rows时候我使用row.delete时总是出现问题了 :)
有些人说我早就知道迭代中不能这样,但你知道原理吗?你知道怎么防止迭代中的错误吗?我估计你也只是看开头的那个黑体字就没往下看了吧,呵呵,你知道不代表你高明,更不用特意表现出来,此文章仅供学习之用,如果你知道,那么请绕道,这是给不知道的人看的,谢谢!
linq to xml的方法,简洁直观,代码量小,下面扯扯本文想要说的万圣节问题,这个词从以下书中来
Pro LINQ: Language Integrated Query in C# 2010
第231页,(Halloween Problem)
那么什么是万圣节问题呢,不说名字怎么来了,书里解释了一下。下面说一下,具体指的是什么
万圣节问题指在迭代一组元素的时候,删除或改变元素个数时,迭代出现的的不正常行为,但这种问题可以避免,同时达到本来要达到的效果
书中的例子
XDocument xDocument = new XDocument( new XElement("BookParticipants", new XElement("BookParticipant", new XAttribute("type", "Author"), new XElement("FirstName", "Joe"), new XElement("LastName", "Rattz")), new XElement("BookParticipant", new XAttribute("type", "Editor"), new XElement("FirstName", "Ewan"), new XElement("LastName", "Buckingham")))); IEnumerable<XElement> elements = xDocument.Element("BookParticipants").Elements("BookParticipant"); foreach (XElement element in elements) { Console.WriteLine("Source element: {0} : value = {1}", element.Name, element.Value); } foreach (XElement element in elements) { Console.WriteLine("Removing {0} = {1} ...", element.Name, element.Value); element.Remove(); } Console.WriteLine(xDocument);
理论上在foreach的时候,每次都调用remove了,所以每次都应该打印出删除的元素,并且父元素下的子
元素应该全部都删除掉了,可是打印出的结果并非如此
Source element: BookParticipant : value = JoeRattz Source element: BookParticipant : value = EwanBuckingham Removing BookParticipant = JoeRattz ... <BookParticipants> <BookParticipant type="Editor"> <FirstName>Ewan</FirstName> <LastName>Buckingham</LastName> </BookParticipant> </BookParticipants>
竟然还剩一个元素没有删除掉!并且也只打印出第一个元素删除掉的那句话。
费解吗?其实linq的执行都是延迟执行的,这是其导致的潜在副作用
书中给出的解决方案是,缓存元素序列,其中用到了 ToArray 操作符
XDocument xDocument = new XDocument( new XElement("BookParticipants", new XElement("BookParticipant", new XAttribute("type", "Author"), new XElement("FirstName", "Joe"), new XElement("LastName", "Rattz")), new XElement("BookParticipant", new XAttribute("type", "Editor"), new XElement("FirstName", "Ewan"), new XElement("LastName", "Buckingham")))); IEnumerable<XElement> elements = xDocument.Element("BookParticipants").Elements("BookParticipant"); foreach (XElement element in elements) { Console.WriteLine("Source element: {0} : value = {1}", element.Name, element.Value); } foreach (XElement element in elements.ToArray()) { Console.WriteLine("Removing {0} = {1} ...", element.Name, element.Value); element.Remove(); } Console.WriteLine(xDocument);
注意LINQ To XML 构建XML树的时候是延迟查询,也就是Console.WriteLine(xDocument); 这句才真正生成XML树,故之前的循环如果不缓存起来,是不可能操作到XML树的
注意这句 XElement element in elements.ToArray()
ToArray在MSDN文档中
http://msdn.microsoft.com/zh-cn/library/bb298736.aspx
有这么一句话
ToArray<TSource>(IEnumerable<TSource>) 方法强制进行直接查询计算,并返回一个包含查询结果的数组。 可将此方法追加到您的查询,以获得查询结果的缓存副本。
接着打印结果变成我们最终想要的那样
Source element: BookParticipant : value = JoeRattz Source element: BookParticipant : value = EwanBuckingham Removing BookParticipant = JoeRattz ... Removing BookParticipant = EwanBuckingham ... <BookParticipants />
如此这般,问题就解决了
我终于也明白为什么之前我在forearch datarow in datatable.rows时候我使用row.delete时总是出现问题了 :)
有些人说我早就知道迭代中不能这样,但你知道原理吗?你知道怎么防止迭代中的错误吗?我估计你也只是看开头的那个黑体字就没往下看了吧,呵呵,你知道不代表你高明,更不用特意表现出来,此文章仅供学习之用,如果你知道,那么请绕道,这是给不知道的人看的,谢谢!
相关文章推荐
- 从另一个方面看 Linq to Xml中的万圣节问题(迭代中的万圣节问题)
- linq to xml 中,html编码的问题
- linq to xml 中,html编码的问题
- Linq to XML用XmlReader读取数据导致无法输出的格式化异常的问题
- Linq to XML:查询不到数据的问题
- Linq to xml 示例分析
- C# 中的默认命名空间的范围 (LINQ to XML)
- LINQ to Entities已知问题及注意事项
- Convert Object to XML using LINQ
- 使用LINQ to SQL更新数据库(上):问题重重
- 使用LinqToXML增删
- 使用Linq to XML 修改app.config
- 【转】LINQ To XML 入门(3)
- C#操作Xml:linq to xml操作XML
- linq to xml操作XML
- LINQ to XML .Net 3.5 中的新XML对象
- LinQ to XML——LinQ to XML操作XML文档
- LINQ to SQL:处理char(1)字段的方式会引起全表扫描问题
- linq to xml(添加节点2)
- Linq to xml:链接轴