The reason this is not an infinite loop is that you list only 10 times according to using the Linq Take (10) call. Now, if you wrote the code something like this:
foreach (var item in Numbers()) { }
Now this is an infinite loop, because your enumerator will always return a new value. The C # compiler takes this code and converts it into a state machine. If your enumerator does not have a security offer to break execution, then the caller must indicate in his example.
The reason code is lazy is also the reason why code works. Essentially, Take returns the first element, then your application consumes, then it takes another, until it accepts 10 elements.
Edit
This actually has nothing to do with adding Take. They are called iterators. The C # compiler performs complex conversion of your code, creating an enumerator from your method. I recommend reading it, but basically (and it may not be 100% accurate), your code will go into the Numbers method, which you could imagine as initializing a state machine.
As soon as your code falls into the return profitability, you basically say that Numbers () stop execution, return this result, and then when they request the next element to be executed on the next line after the return returns.
Eric Lippert has an excellent series on different aspects of iterators
Joshberry
source share