在 C# 中实现双向枚举器
有没有办法使用yield块来实现可以向后(MoveLast()
)以及向前移动的IEnumerator
?
Is there a way to use yield blocks to implement an IEnumerator<T>
which can go backward (MoveLast()
) as well as forward?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
不是直接来自迭代器块,不是。
但是,调用者始终可以缓冲结果,例如缓冲到
List
中,或者仅调用Reverse()
- 但这并不总是适用。Not directly from the iterator block, no.
However, the caller can always buffer the results, for example into a
List<T>
, or just callReverse()
- but this doesn't always apply.不,C# 编译器生成的状态机是严格前向的。
在很多情况下,倒退甚至没有意义。 想象一下迭代器从网络流中读取数据 - 要向后移动,它必须记住它曾经读取过的所有内容,因为它无法倒带时间并再次向网络请求数据。
(任何以某种有损方式生成数据的东西也是如此。想象一个迭代器在每次迭代中为康威的生活返回一个新板 - 有多个板可能都是前一个板,所以要倒退你必须再次记住你已经返回的内容。)
No, the state machine generated by the C# compiler is strictly forward.
It doesn't even make sense to go backwards in many cases. Imagine an iterator reading from a network stream - to go backwards, it would have to remember everything that it had ever read, because it couldn't rewind time and ask the network for the data again.
(Ditto anything that generated data in some lossy way. Imagine an iterator which returned a new board for Conway's Life on each iteration - there are multiple boards which could all have been the previous one, so to go backwards you again have to remember what you've already returned.)
我知道这个线程非常旧,但值得注意的是
...被编译成:
所以如果您不介意“MoveNext”语法,您可以轻松实现 IEnumerator 并添加“MovePrevious”。 如果使用“foreach”,则无法反转方向,但如果使用 while 循环,则可以反转方向。
或者...如果您想以相反方向(不是双向)“foreach”列表,您可以利用yield 语句。
或者...如果您想通过走很长的路线来反向进行 foreach,您可以实现自己的 IEnumerable/IEnumerator
I know this thread is super old but it is relevant to note that
... is get compiled into:
So if you don't mind the "MoveNext" syntax, you could easily implement IEnumerator and add a "MovePrevious". You wouldn't be able to reverse direction if you use "foreach" but you'd be able to reverse direction if using a while loop.
Or... if you want to "foreach" a list in reverse direction (not bidirectional) you could take advantage of the yield statement.
Or... if you want to foreach in reverse by going the long route you can implement your own IEnumerable/IEnumerator
C5 集合库 (http://www.itu.dk/research/c5/)
使用向后枚举实现集合和链表。 该项目是开源的,因此您应该能够在那里找到答案。
C5 Collections library (http://www.itu.dk/research/c5/)
implements collections and linked list with backwards enumeration. The project is OpenSource so you should be able to find answer there.
不可以。IEnumerator 的局限性之一是它保留当前状态,并且不记得之前的状态。 因此,IEnumerable 是只向前的。
如果您需要保留先前的状态,请将 IEnumerable 读入 List 或 LinkedList 并枚举这些对象。
No. One of the limitations of IEnumerator is that it holds its current state, and it doesn't remember its prior state. As a result, IEnumerable is forward-only.
If you need to hold onto prior states, read the IEnumerable into a List or LinkedList and enumerate through those objects instead.
实际上,似乎有一种方法描述于 加速 C# 2008< /a>. 不幸的是,两个页面在预览中不可见,并且它必须依赖于反射(其结果可以像往常一样被缓存),但您可以了解要点。
Actually, there seems to be an approach described in Accelerated C# 2008. Unfortunately, two pages are not visible in the preview, and it has to rely on reflection (the results of which can be cached, as usual) but you can get the gist.
不会。使用
yield
会导致IEnumerable
这是单向的。No. Using
yield
results in anIEnumerable
which is unidirectional.