for bucle array c# foreach verbosity

c# - bucle - ¿Es mejor la práctica de codificación definir variables fuera de un foreach aunque sea más detallado?



foreach c# list (12)

En los siguientes ejemplos:

  • El primero parece más detallado pero menos desperdiciado de recursos.
  • el segundo es menos detallado pero más desperdicio de recursos (redefine la cadena de cada bucle)

¿Cuál es la mejor práctica de codificación?

Primer ejemplo:

using System; using System.Collections.Generic; namespace TestForeach23434 { class Program { static void Main(string[] args) { List<string> names = new List<string> { "one", "two", "two", "three", "four", "four" }; string test1 = ""; string test2 = ""; string test3 = ""; foreach (var name in names) { test1 = name + "1"; test2 = name + "2"; test3 = name + "3"; Console.WriteLine("{0}, {1}, {2}", test1, test2, test3); } Console.ReadLine(); } } }

Segundo ejemplo:

using System; using System.Collections.Generic; namespace TestForeach23434 { class Program { static void Main(string[] args) { List<string> names = new List<string> { "one", "two", "two", "three", "four", "four" }; foreach (var name in names) { string test1 = name + "1"; string test2 = name + "2"; string test3 = name + "3"; Console.WriteLine("{0}, {1}, {2}", test1, test2, test3); } Console.ReadLine(); } } }


Ambas son prácticamente iguales en cuanto al rendimiento (las cadenas son inmutables), pero en cuanto a la legibilidad ... Yo diría que ninguna de las dos es muy buena. Fácilmente podría hacerlo todo dentro de la Console.WriteLine.

¿Quizás puedas publicar el problema real en lugar de un ejemplo?


Creo que depende de lo que estés tratando de resolver. Me gusta el segundo ejemplo, porque puedes mover el código en un solo paso. Me gusta el primer ejemplo, porque es más rápido debido a menos manipulaciones de pila, menos fragmentación de memoria y menos construcción / creación de objetos.


Dependiendo del idioma y del compilador puede o no ser el mismo. Para C # espero que el código resultante sea muy similar.

Mi propia filosofía sobre esto es simple:

Optimizar para facilitar la comprensión.

¡Cualquier otra cosa es optimización prematura! El mayor cuello de botella en la mayoría de los desarrollos es el tiempo y la atención del desarrollador. Si es absolutamente necesario exprimir hasta el último ciclo de la CPU, hágalo con toda seguridad, pero a menos que tenga una necesidad empresarial convincente o escriba un componente crítico (biblioteca común, kernel del sistema operativo, etc.) es mejor que espere hasta que Se puede comparar el programa terminado. En ese momento, se justifica la optimización de algunas de las rutinas más costosas, antes de eso es casi una pérdida de tiempo.


Descubrí que las declaraciones de ''levantamiento'' fuera de los bucles suelen ser una mejor estrategia a largo plazo para el mantenimiento. El compilador usualmente ordenará las cosas de manera aceptable para el rendimiento.


Esos son a la vez derrochadores y verbosos.

foreach (var name in names) { Console.WriteLine("{0}1, {0}2, {0}3", name); }

.

</tongueincheek>


Esta es mi parte favorita de Linq, que creo que encaja aquí:

names.ForEach(x => Console.WriteLine("{0}1, {0}2, {0}3", x));


Generalmente declaro las variables tan cerca de su uso como lo permita el alcance, que en este caso sería su segundo ejemplo. Resharper tiende a fomentar este estilo también.


La segunda forma no es más derrochadora, simplemente es mejor.

No hay ninguna ventaja de declarar las variables fuera del bucle, a menos que desee mantener sus valores entre iteraciones.

(Tenga en cuenta que generalmente esto no hace ninguna diferencia de comportamiento, pero eso no es cierto si las variables están siendo capturadas por una expresión lambda o un método anónimo).


No estoy seguro de lo que obtienes al definir la variable de cadena fuera del bucle. Las cuerdas son inmutables por lo que no se reutilizan. Cada vez que se les asigna, se crea una nueva instancia.


Para los datos de tipo POD declarar más cercano al primer uso. Para cualquier cosa como una clase que hace cualquier asignación de memoria, entonces debería considerar declarar aquellos fuera de cualquier bucle. Es probable que las cadenas hagan algún tipo de asignación y la mayoría de las implementaciones (al menos en C ++) intentarán reutilizar la memoria si es posible. Las asignaciones basadas en el montón pueden ser realmente muy lentas.

Una vez hice un perfil de un poco de código C ++ que incluía una clase que incluía datos nuevos en su ctor. Con la variable declarada fuera del bucle, se ejecutó un 17% más rápido que con la variable declarada dentro del bucle. YMMV en C # para que el rendimiento del perfil le sorprenda mucho con los resultados.


Personalmente, creo que es la mejor práctica declarar las variables en el ámbito más estricto posible, dado su uso.

Esto proporciona muchos beneficios:

  1. Es más fácil para refactorizar, ya que la extracción de un método es más simple cuando las variables ya están en el mismo ámbito.
  2. El uso variable es más claro, lo que llevará a un código más confiable.

La única desventaja (potencial) sería la declaración de la variable adicional; sin embargo, el JIT tiende a optimizar este problema, por lo que no me preocuparía necesariamente en el trabajo real.

La única excepción a esto:

Si su variable va a agregar mucha presión del GC, y si esto puede evitarse reutilizando la misma instancia de objeto a través del bucle foreach / for, y si la presión del GC está causando problemas de rendimiento medidos , lo elevaré a El alcance exterior.


Siga una regla simple al declarar variables

Declara cuando la necesites por primera vez.