2010-03-15 8 views
18

Duplicar posible:
How does foreach work when looping through function results?C# - ¿Se llama a la función para cada iteración de un bucle foreach?

Si tengo funcionalidades como las siguientes - se ReturnParts() ser llamado para cada iteración de un bucle foreach, o va a ser llamado sólo una vez ?

private void PrintParts() 
{ 
    foreach(string part in ReturnParts()) 
    { 
     // Do Something or other. 
    } 
} 

private string[] ReturnParts() 
{ 
    // Build up and return an array. 
} 
+1

duplicado: http://stackoverflow.com/questions/1632810/how-does-foreach-work-when-looping-through-function-results –

Respuesta

25

Se llamará solo una vez.

P.S. Llamarlo varias veces tendría poco sentido. Lo volvería a llamar cada vez que esperaba que el resultado fuera diferente cada vez. ¿Y cómo iterarías sobre un conjunto que cambia continuamente?

9

Solo se llamará una vez.

The foreach loop is equivalent to the following code:

IEnumerable<string> enumerator = (collection).GetEnumerator(); 
try { 
    while (enumerator.MoveNext()) { 
     string part = (string)enumerator.Current; 

     // Do Something or other. 

    } 
} finally { 
    IDisposable disposable = enumerator as System.IDisposable; 
    if (disposable != null) disposable.Dispose(); 
} 
17

Se puede determinar esto por sí mismo mediante la colocación de un punto de interrupción en la función "ReturnParts" Si es impacta mutliple veces para cada iteración, entonces sí que lo hace.

+0

Apreciar la sugerencia. Esta es una buena manera de descubrir las respuestas a sus propias preguntas –

6

Al pensar en las diferencias entre for, foreach, while y goto hace unas semanas, escribí este código de prueba. Todos los métodos se compilarán en la misma IL (a excepción de un nombre de variable en la versión foreach). En el modo de depuración, algunas declaraciones NOP estarán en diferentes posiciones.

static void @for<T>(IEnumerable<T> input) 
{ 
    T item; 
    using (var e = input.GetEnumerator()) 
     for (; e.MoveNext();) 
     { 
      item = e.Current; 
      Console.WriteLine(item); 
     } 
} 
static void @foreach<T>(IEnumerable<T> input) 
{ 
    foreach (var item in input) 
     Console.WriteLine(item); 
} 
static void @while<T>(IEnumerable<T> input) 
{ 
    T item; 
    using (var e = input.GetEnumerator()) 
     while (e.MoveNext()) 
     { 
      item = e.Current; 
      Console.WriteLine(item); 
     } 
} 
static void @goto<T>(IEnumerable<T> input) 
{ 
    T item; 
    using (var e = input.GetEnumerator()) 
    { 
     goto check; 
    top: 
     item = e.Current; 
     Console.WriteLine(item); 
    check: 
     if (e.MoveNext()) 
      goto top; 
    } 
} 
static void @gotoTry<T>(IEnumerable<T> input) 
{ 
    T item; 
    var e = input.GetEnumerator(); 
    try 
    { 
     goto check; 
    top: 
     item = e.Current; 
     Console.WriteLine(item); 
    check: 
     if (e.MoveNext()) 
      goto top; 
    } 
    finally 
    { 
     if (e != null) 
      e.Dispose(); 
    } 
} 

por @ el comentario de Eric ...

he ampliado for, while, 'Goto' y foreach con matrices genéricas. Ahora la declaración for each busca usar el indexador para la matriz. Las matrices y cadenas de objetos se expanden de manera similar. Los objetos eliminarán un boxeo que ocurra antes de que el método llame a Console.WriteLine y Strings reemplazará a T item y T[] copy... con char item y string copy... respectivamente. Tenga en cuenta que la sección crítica ya no es necesaria porque el enumerador desechable ya no se utiliza.

static void @for<T>(T[] input) 
{ 
    T item; 
    T[] copy = input; 
    for (int i = 0; i < copy.Length; i++) 
    { 
     item = copy[i]; 
     Console.WriteLine(item); 
    } 
} 
static void @foreach<T>(T[] input) 
{ 
    foreach (var item in input) 
     Console.WriteLine(item); 
} 
static void @while<T>(T[] input) 
{ 
    T item; 
    T[] copy = input; 
    int i = 0; 
    while (i < copy.Length) 
    { 
     item = copy[i]; 
     Console.WriteLine(item); 
     i++; 
    } 
} 
static void @goto<T>(T[] input) 
{ 
    T item; 
    T[] copy = input; 
    int i = 0; 
    goto check; 
top: 
    item = copy[i]; 
    Console.WriteLine(item); 
    i++; 
check: 
    if (i < copy.Length) 
     goto top; 
} 
+0

@gotoTry es la versión más expandida que se me ocurre sin mostrar el IL compilado. –

+2

Bien hecho. Por supuesto, esta es la expansión solo para cosas que implementan IEnumerable . foreach genera código diferente para matrices y cadenas. –

+0

@Eric: gracias por la retroalimentación. Iba a la versión más genérica, pero puedo extender esto más adelante. (Estaba interesado principalmente en la versión goto, ya que la mayoría todavía la consideraba "malvada"). –

Cuestiones relacionadas