Как работает foreach при циклическом просмотре результатов функции?
Вопрос
Предположим, у меня есть следующий код:
foreach(string str in someObj.GetMyStrings())
{
// do some stuff
}
Будет someObj.GetMyStrings()
вызываться на каждой итерации цикла?Было бы лучше вместо этого сделать следующее:
List<string> myStrings = someObj.GetMyStrings();
foreach(string str in myStrings)
{
// do some stuff
}
?
Решение
Функция вызывается только один раз, чтобы вернуть IEnumerator<T>
;после этого, в MoveNext()
метод и Current
свойства используются для перебора результатов:
foreach (Foo f in GetFoos())
{
// Do stuff
}
в некоторой степени эквивалентно:
using (IEnumerator<Foo> iterator = GetFoos().GetEnumerator())
{
while (iterator.MoveNext())
{
Foo f = iterator.Current;
// Do stuff
}
}
Обратите внимание, что итератор удаляется в конце - это особенно важно для удаления ресурсов из блоков итератора, например:
public IEnumerable<string> GetLines(string file)
{
using (TextReader reader = File.OpenText(file))
{
string line;
while ((line = reader.ReadLine()) != null)
{
yield return line;
}
}
}
В приведенном выше коде вы действительно хотите, чтобы файл был закрыт по завершении итерации, и компилятор реализует IDisposable
хитроумно, чтобы это сработало.
Другие советы
Нет..функция будет вызвана один раз, чтобы получить IEnumerable ..и затем будет повторный вызов MoveNext и Current.
GetMyStrings() повторно запускает объект типа IEnumerable.Среда выполнения знает, как с этим справиться.Он вызывает IEnumerable.GetEnumerator(), а затем для этого объекта enumerator вызывает MoveNext() и Current .
Просто чтобы закруглить вопрос на случай, если вы впадете в "все за одно и то же".;для(int x=0;x < ProvideCeiling() Обеспечить закрытие();x++) делает вызывайте эту функцию каждый раз.