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

发布于 2024-08-30 16:36:20 字数 698 浏览 3 评论 0原文

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

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() 将 XElement 转储到列表中,我认为这可行,但我不确定这是“最佳实践”。预先感谢您的任何建议!

What is the “best practice” way of manually iterating (i.e., one at a time with a “next” button) over a set of XElements in my XDocument? Say I select the set of elements I want thusly:

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

I can use an IEnumerator to iterate over them, i.e.,
IEnumerator m_iter;

But when I get to the end and I want to wrap around to the beginning if I call Reset() on it, it throws a NotSupportedException. That’s because, as the Microsoft C# 2.0 Specification under chapter 22 "Iterators" says "Note that enumerator objects do not support the IEnumerator.Reset method. Invoking this method causes a System.NotSupportedException to be thrown ."

So what IS the right way of doing this? And what if I also want to have bidirectional iteration, i.e., a “back” button, too?

Someone on a Microsoft discussion forum said I shouldn’t be using IEnumerable directly anyway. He said there was a way to do what I want with LINQ but I didn’t understand what. Someone else suggested dumping the XElements into a List with ToList(), which I think would work, but I wasn’t sure it was “best practice”. Thanks in advance for any suggestions!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

并安 2024-09-06 16:36:20

解决方案非常简单。只需从 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() 它会解析所有后代元素一次并将它们加载到内存中。

The solution is very simple. Just create a List out of your XElements collection.

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

You can enumerate through it via the indexer elems[i] and jump back and forth. Just store the current index in a variable, and decrement/increment it on a button click (with wrap-around).

The xml you have is parsed on demand by your linq query (see MSDN for deferred execution and lazy evaluation in Linq to XML). Even if it would support IEnumerable.Reset(), it would have to parse it again every time. If you call .ToList<T>() it parses all descendant elements once and loads them into the memory.

夜血缘 2024-09-06 16:36:20

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

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

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

It is very rare you need to use the enumerator directly; just use foreach on elems. Here's iterating it twice:

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

No need for Reset() - it simply uses GetEnumerator() twice for you, which is the correct way of doing it. If you can't run the query twice for whatever reason, or want random access rather than sequential, then you'll have to buffer it - perhaps into a list with ToList().

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文