2009-12-10 28 views
63

¿Cuál de estos es el más rápido/mejor?Declarar una variable dentro o fuera de un bucle foreach: ¿cuál es más rápido/mejor?

Ésta:

List<User> list = new List<User>(); 
User u; 

foreach (string s in l) 
{ 
    u = new User(); 
    u.Name = s; 
    list.Add(u); 
} 

O esta otra:

List<User> list = new List<User>(); 

foreach (string s in l) 
{ 
    User u = new User(); 
    u.Name = s; 
    list.Add(u); 
} 

Mis habilidades novato-desarrollo me dice que el primero es mejor, pero un amigo mío me dice im mal, pero podría No me da una buena razón por la cual el segundo es mejor.

¿Hay alguna diferencia en el rendimiento en absoluto?

Respuesta

77

En cuanto a rendimiento, ambos ejemplos se compilan en la misma IL, por lo que no hay diferencia.

El segundo es mejor, porque expresa más claramente su intención si u solo se usa dentro del bucle.

+9

Tenga en cuenta que no es * * una diferencia si la variable es capturado por una expresión lambda o delegado anónimo; ver [Trampa de Variable Exterior] (http://stackoverflow.com/q/3416758). – dtb

+0

¿Puede explicar por qué ambos se compilan en la misma IL? Estoy bastante seguro de que C# no eleva las declaraciones de variables hasta la parte superior de la función como lo hace javascript. – styfle

+3

@styfle aquí está [la respuesta] (http://stackoverflow.com/questions/1884906/declaring-a-variable-inside-or-outside-an-foreach-loop-which-is-faster-better#comment1785311_1884957) a tu pregunta. –

1

El segundo es mejor. Quiere decir tener un nuevo usuario en cada iteración.

0

No debe haber diferencias perceptibles en el rendimiento.

1

Técnicamente, el primer ejemplo ahorrará algunos nanosegundos porque no será necesario mover el marco de la pila para asignar una nueva variable, pero esta es una cantidad tan pequeña de tiempo de CPU que no lo notará, eso es si el compilador no optimiza ninguna diferencia de ninguna manera.

+0

Estoy bastante seguro de que CLR no asigna "una nueva variable" en cada iteración de un ciclo. – dtb

+0

Bueno, el compilador puede optimizar eso, pero el espacio de pila debe asignarse para cualquier variable en un bucle. Esto dependería de la implementación y una implementación simplemente mantendría el marco de pila igual, mientras que otro (por ejemplo, Mono) podría liberar la pila y luego volver a crearla en cada ciclo. –

+11

Todas las variables locales en un método (nivel superior o anidado en un bucle) se compilan a variables de nivel de método en IL. El espacio para las variables se asigna antes de que se ejecute el método, no cuando se alcanza una rama con la declaración en C#. – dtb

6

Una declaración no hace que se ejecute ningún código, por lo que no es un problema de rendimiento.

El segundo es lo que quieres decir, y es menos probable que cometas un error estúpido si lo haces de la segunda manera, así que úsalo. Intente siempre declarar las variables en el alcance más pequeño que sea necesario.

Y, además, la mejor manera es utilizar LINQ:

List<User> users = l.Select(name => new User{ Name = name }).ToList(); 
+2

Me encanta la línea "Intente siempre declarar las variables en el menor alcance necesario". Creo que una sola línea puede responder muy bien la pregunta. – Manjoor

1

En este escenario, la segunda versión es mejor.

En general, si solo necesita acceder al valor dentro del cuerpo de la iteración, entonces elija la segunda versión. Por otro lado, si hay algún estado final, la variable se mantendrá más allá del cuerpo del ciclo, entonces declara y luego usa la primera versión.

11

En cualquier caso, la mejor manera sería utilizar un constructor que toma un nombre ... o, de otro modo, explotar rizado corsé notación:

foreach (string s in l) 
{ 
    list.Add(new User(s)); 
} 

o

foreach (string s in l) 
{ 
    list.Add(new User() { Name = s }); 
} 

o aún mejor, LINQ:

var list = l.Select(s => new User { Name = s}); 

Ahora, mientras el primer ejemplo podría, en algunos casos, ser unperceptibly más rápido, el segundo en e es mejor porque es más legible y el compilador puede descartar la variable (y omitirla por completo) ya que no se usa fuera del alcance de foreach.

+4

Comentario necrófilo del día: "o incluso mejor, LINQ". Claro que es una línea de código, y eso nos hace sentir como buenos desarrolladores. Pero la versión de cuatro líneas es mucho más comprensible y, por lo tanto, se puede mantener. –

+3

Apenas. Con la versión de LINQ, sé que lo que estoy haciendo es inmutable y funciona con todos los elementos. – Tordek

3

Cuando tenga una pregunta sobre el rendimiento, lo único que debe hacer es medir, ejecutar un ciclo alrededor de su prueba y medir el tiempo.

Para responder a su pregunta, sin medir :-) o mirar las ilasm generadas, cualquier diferencia no se notaría en un número significativo de iteraciones y la operación más cara en su código probablemente sea la asignación del usuario por unos pocos órdenes de magnitud, así que concéntrate en la claridad del código (como deberías en general) y ve con 2.

Oh, es tarde y creo que solo estoy tratando de decir que no te preocupes por este tipo de cosa o quedar atrapado en detalles como este.

K

+0

thx para la propina, creo que voy a cronometrar algunas otras cosas que he estado persiguiendo así como jeje: D – Marcus

+0

Si quieres ir más lejos con la búsqueda de lo que afecta el rendimiento, busca usando un generador de perfiles de código. Si nada más, comenzará a darle una idea de qué tipo de código y operaciones toman más tiempo. ProfileSharp y EqatecProfilers son gratuitos y suficientes para comenzar. –

Cuestiones relacionadas