Повторный перебор в C#
Каждый foreach запрашивает у коллекции новый IEnumerator через GetEnumerator. Один экземпляр перечислителя после прохода остаётся в конце последовательности - повторный MoveNext без сброса не вернёт элементы с начала.
Список при каждом foreach выдаёт свежий перечислитель, поэтому два прохода дают одну и ту же сумму. Генератор без сохранённой копии на втором проходе выполняет тело заново.
Дважды просуммируем одну и ту же пару отдельными циклами. Метка "run" стоит в начале генератора, поэтому она печатается заново на каждом проходе: тело выполняется с начала, а не продолжает старый перечислитель. Если сохранить один IEnumerator и вызвать MoveNext после конца, без Reset, которого у многих типов нет, повторного обхода не будет:
static IEnumerable<int> Pair()
{
Console.WriteLine("run"); // выведет run
yield return 3;
yield return 4;
}
int first = 0;
foreach (int x in Pair()) first += x;
int second = 0;
foreach (int x in Pair()) second += x;
Console.WriteLine(first); // выведет 7
Console.WriteLine(second); // выведет 7
Дважды просуммируйте цены 8 и 1 отдельными циклами и выведите обе суммы.