How it works
An iterator method returns a sequence by using yield return. Calling Squares creates an enumerable operation; it does not eagerly calculate and store every square. Enumeration enters the body and advances until the next yielded value. Take requests only the first two items, so the loop does not need to produce the square of three. This supports pipelines that can stop early.
It also means side effects inside an iterator happen during enumeration and can happen again when the sequence is enumerated again. Keep the iterator’s input and lifetime requirements clear, especially if its body accesses mutable data.
Add a diagnostic WriteLine immediately before yield return and observe how Take stops requests. Enumerate the same query twice and count how many diagnostic messages appear.
A working example
using System;
using System.Linq;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
foreach (var square in Squares(4).Take(2)) Console.WriteLine(square);
IEnumerable<int> Squares(int count)
{
for (var i = 1; i <= count; i++) yield return i * i;
}
Expected output
1 4
An iterator describes how to obtain values; enumeration asks for them.