在我的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中,我觉得这样可行,但我不确定它是“最佳实践”。提前感谢任何建议!
答案 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()
的列表中。