¿Cómo funciona foreach cuando se repiten los resultados de las funciones?

Supongamos que tengo el siguiente código:

foreach(string str in someObj.GetMyStrings()) { // do some stuff } 

¿Se someObj.GetMyStrings() en cada iteración del ciclo? ¿Sería mejor hacer lo siguiente en su lugar?

 List myStrings = someObj.GetMyStrings(); foreach(string str in myStrings) { // do some stuff } 

?

La función solo se llama una vez para devolver un IEnumerator ; después de eso, el método MoveNext() y la propiedad Current se usan para iterar a través de los resultados:

 foreach (Foo f in GetFoos()) { // Do stuff } 

es algo equivalente a:

 using (IEnumerator iterator = GetFoos().GetEnumerator()) { while (iterator.MoveNext()) { Foo f = iterator.Current; // Do stuff } } 

Tenga en cuenta que el iterador está dispuesto al final; esto es particularmente importante para eliminar recursos de bloques de iteradores, por ejemplo:

 public IEnumerable GetLines(string file) { using (TextReader reader = File.OpenText(file)) { string line; while ((line = reader.ReadLine()) != null) { yield return line; } } } 

En el código anterior, realmente desea que el archivo se cierre cuando termine de iterar, y el comstackdor implementa IDisposable astutamente para que funcione.

No … la función se llamará una vez para obtener el IEnumerable … y luego habrá una llamada repetida a MoveNext y Current.

GetMyStrings () vuelve a incluir un objeto de tipo IEnumerable. El tiempo de ejecución sabe cómo lidiar con eso. Llama a IEnumerable.GetEnumerator () y luego en ese objeto del enumerador llama a MoveNext () y Current.

Solo para redondear la pregunta en caso de que caiga en un “todo para siempre es lo mismo”; for (int x = 0; x