手动迭代选择的XML元素(C#,XDocument)

时间:2010-04-27 21:38:47

标签: c# .net xml iterator linq-to-xml

在我的XDocument中的一组XElements上手动迭代(即,一次一个带有“下一个”按钮)的“最佳实践”方法是什么?假设我选择了我想要的元素集:

var elems = from XElement el in m_xDoc.Descendants()
            where (el.Name.LocalName.ToString() == "q_a") 
            select el;

我可以使用IEnumerator迭代它们,即     IEnumerator m_iter;

但是当我到达最后并且如果我在其上调用Reset()时我想绕回到开头,它会抛出NotSupportedException。这是因为,正如第22章“迭代器”中的Microsoft C#2.0规范所说“请注意,枚举器对象不支持IEnumerator.Reset方法。调用此方法会导致抛出System.NotSupportedException 。”

那么这样做的正确方法是什么?如果我也想要双向迭代,也就是“后退”按钮呢?

微软讨论论坛上有人说我不应该直接使用IEnumerable。他说有一种方法可以用LINQ做我想做的事,但我不知道是什么。其他人建议将XElements转储到带有ToList()的List中,我觉得这样可行,但我不确定它是“最佳实践”。提前感谢任何建议!

2 个答案:

答案 0 :(得分:1)

解决方案非常简单。只需从XElements集合中创建一个List。

var elems = (from XElement el in m_xDoc.Descendants()
            where (el.Name.LocalName.ToString() == "q_a") 
            select el).ToList();

您可以通过索引器elems[i]枚举它并来回跳转。只需将当前索引存储在变量中,然后在单击按钮时递减/递增它(使用环绕)。

您拥有的xml将根据您的linq查询进行解析(请参阅MSDN for deferred execution and lazy evaluation in Linq to XML)。即使它支持IEnumerable.Reset(),它也必须每次都再次解析它。如果你调用.ToList<T>(),它会解析所有后代元素并将它们加载到内存中。

答案 1 :(得分:1)

非常很少需要直接使用枚举器;只需在foreach上使用elems即可。这里重复两次:

// first time
foreach(var item in elems) {...}
// second time
foreach(var item in elems) {...}

不需要Reset() - 它只是使用GetEnumerator()两次为你,这是正确的方法。如果由于某种原因无法运行查询两次,或者想要随机访问而不是顺序访问,那么您必须缓冲它 - 可能会将其缓存到ToList()的列表中。