Каждый раз, когда вы перебираете people
, он снова выполняет код в GetPeople()
- создавая новые экземпляры Person
. Код в GetPeople
не не запускается при вызове GetPeople()
; он запускается только при вызове чего-либо:
var iterator = people.GetEnumerator();
iterator.MoveNext();
... это то, что делает цикл foreach
.
Если вы вызываете ToList()
, это означает, что вы выполняете код только в GetPeople()
один раз и сохраняете ссылки, возвращаемые при итерации по последовательности. В этот момент каждый раз, когда вы выполняете итерацию по List<Person>
, вы будете выполнять итерации по ссылкам на одни и те же объекты, поэтому любые изменения, сделанные вами в одном цикле, будут видны в другом.
Возможно, вам будет немного легче понять, что происходит, если вы установите логирование (или точку останова) в GetPeople()
. У меня есть статья , в которой подробно описывается реализация, которая может также прояснить ситуацию.