2009-10-04 8 views
9

Si escribir DECLARACIÓN foreach en C#:foreach en C# recálculo

foreach(String a in veryComplicatedFunction()) 
{ 

} 

¿Va a calcular veryComplicatedFunction cada iteración o sólo una vez, y almacenarlo en alguna parte?

+19

Puede agregar Debug.WriteLine() a veryComplicatedFunction() y descubrirlo usted mismo. – Chris

Respuesta

38

Su pregunta se responde por la sección 8.8.4 de la especificación, que establece:


Los pasos anteriores, si tiene éxito, producen de forma inequívoca un tipo de colección C, E y tipo enumerador elemento tipo T. Una declaración foreach de la forma

foreach (V v in x) embedded-statement 

A continuación se expande a:

{ 
    E e = ((C)(x)).GetEnumerator(); 
    try { 
     V v; 
     while (e.MoveNext()) { 
      v = (V)(T)e.Current; 
      embedded-statement 
     } 
    } 
    finally { 
     … // Dispose e 
    } 
} 

Como se puede ver, en la expansión de la expresión x sólo se evalúa una vez.

18

Sólo se calculará una vez

5

veryComplicatedFunction probable vuelve IEnumerable<string>, que debe suponer que se trata de cálculos se realizan una sola vez y arroyos sus resultados de alguna manera. Sin embargo, sin ver el método real, no hay forma de garantizar lo que hace. Lo que está garantizado es que veryComplicatedFunction solo se llama una vez, lo que hace el foreach es iterar a través de los retornos de un método.

1

Debería calcularlo solo una vez. Como nota al margen, la función muy complicada() debe devolver un IEnumerable o IEnumerable<T> o cualquier objeto que tenga un método público GetEnumerator().

+8

En realidad, su nota al margen no es correcta. Siempre que devuelva un objeto que tenga un método GetEnumerator que no tome parámetros y devuelva un IEnumerator o derivación del mismo, funcionará con la instrucción foreach. La clase en sí no necesita implementar IEnumerable. –

+0

Vaya, tienes razón. Voy a corregir mi respuesta. Tenía la impresión de que para hacer un foreach el tipo subyacente debe ser un IEnumerable. Parece que el compilador está feliz siempre que haya una definición pública de GetEnumerator() disponible. Interesante ... –

+0

Un ejemplo de tipado de patos en.net ;-) (creo que aún no hay otros) –

6

Depende de lo que quiera decir con una vez. Si usted tiene un método como el siguiente:

public static IEnumerable<int> veryComplicatedFunction() 
{ 
    List<string> l = new List<string> { "1", "2", "3" }; 
    foreach (var item in l) 
    { 
     yield return item; 
    } 
} 

control sería devuelto al método llamando veryComplicatedFunction después de cada rendimiento. Entonces, si estuvieran compartiendo la Lista l, podrían obtenerse resultados extraños. Una forma segura de eliminar ese tipo de problema sería llamar a la extensión ToArray en la función muy simple.

0

Si lo calculó cada vez, podría causar un gran dolor si su función se basó en algo dinámico como la hora actual. Debería calcularlo una vez.