📜 ⬆️ ⬇️

Implementing Iterators in C # (Part 2)

Implementing iterators in C # (part 1) .

Now, when you have in your baggage a general idea of ​​what is behind iterators, you can already answer some questions about their use. Here is a scenario based on real events:

I have a large and complex iterator, and I want to refactor it. For greater clarity, let's agree that the enumerator counts from 1 to 100 twice. (Of course, in real life, the iterator will not be so simple.)
IEnumerable<int> CountTo100Twice() { int i; for (i = 1; i <= 100; i++) { yield return i; } for (i = 1; i <= 100; i++) { yield return i; } } 

As we know from Pragramming 101, we can move the common code into a subroutine and call it. But when I do this, I get a compiler error:
 IEnumerable<int> CountTo100Twice() { CountTo100(); CountTo100(); } void CountTo100() { int i; for (i = 1; i <= 100; i++) { yield return i; } } 

What am I doing wrong? How can I transfer “counting to 100” into a subroutine and call it twice from the CountTo100Twice function?

As we just saw, iterators are not subroutines at all. The technique presented above would work perfectly if we built iterators of, say, fibers instead of finite automata. But since automata are used, yield return expressions must be located at the “top level”. So how are you going to iterate with subroutines?
')
You make the subroutine itself an iterator, and then “pull” the results from the main function:
 IEnumerable<int> CountTo100Twice() { foreach (int i in CountTo100()) yield return i; foreach (int i in CountTo100()) yield return i; } IEnumerable<int> CountTo100() { for (i = 1; i <= 100; i++) { yield return i; } } 

Exercise: Consider the following snippet:
 foreach (int i in CountTo100Twice()) { // ... } 

Explain what will happen on the 150th (fifty-fifth) call to MoveNext () in the loop above. Consider the implications of this for recursive algorithms (such as tree traversal).

Source: https://habr.com/ru/post/136864/


All Articles