手动遍历 XML 元素的选择(C#,XDocument)

3

如何以最佳实践的方式手动迭代(即一次一个,使用“下一个”按钮)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。这是因为,正如Microsoft C# 2.0规范中的第22章“迭代器”所述:“请注意,枚举器对象不支持IEnumerator.Reset方法。调用此方法会导致抛出System.NotSupportedException。”那么正确的做法是什么呢?如果我还想进行双向迭代,即还要有一个“后退”按钮,该怎么办呢?
Microsoft讨论论坛上的某个人说我根本不应该直接使用IEnumerable。他说有一种使用LINQ实现我想要的方式,但我不明白是什么。还有人建议使用ToList()将XElements转储到列表中,我认为这可能有效,但我不确定它是否是“最佳实践”。感谢您提前提供任何建议!
2个回答

1

解决方案非常简单。只需从您的XElements集合中创建一个列表即可。

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

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

你的 XML 是按需由 LINQ 查询解析的(请参阅 MSDN Linq to XML 中的延迟执行和惰性评估)。即使它支持 IEnumerable.Reset(),每次都必须重新解析它。如果调用 .ToList<T>(),它会一次解析所有后代元素并将它们加载到内存中。


1

你很少需要直接使用枚举器;只需在elems上使用foreach即可。这里演示了两次迭代:

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

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


我认为 foreach 循环不是 OP 在寻找的。他想要只在用户按下按钮时获取下一个元素。我认为最好将数据存储到列表中。 - Philip Daubmeier

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接