lenguaje funciona español else ejemplos condiciones como clases anidado anidadas c# resharper nested-loops continue

funciona - C#: condicionales anidados vs declaración de continuación



if c# español (10)

Al usar ReSharper recientemente, está sugiriendo que reduzco el anidamiento en ciertos lugares invirtiendo if condiciones y usando las declaraciones de continue .

condicionales anidados:

foreach(....) { if(SomeCondition) { //do some things if(SomeOtherNestedCondition) { //do some further things } } }

continuar las declaraciones:

foreach(....) { if(!SomeCondition) continue; //do some things if(!SomeOtherNestedCondition) continue; //do some further things }

Entiendo algo de la lógica de por qué querría reducir el anidamiento por problemas de rendimiento y memoria, y cómo los dos fragmentos se comparan entre sí, sin embargo, desde mi experiencia en desarrollo, el ejemplo anterior es más fácil de seguir al leer el código.

¿Qué enfoque prefiere y por qué? ¿Utiliza continue sobre anidado ifs en su código de todos los días?


sin embargo, desde mi experiencia en desarrollo, el ejemplo anterior es más fácil de seguir al leer el código.

Bueno, creo que esa es tu opinión personal. Yo, por ejemplo, trato de evitar tal anidación, ya que hace que el código sea más difícil de leer en mi opinión.

Si le gusta la versión "anterior" más que la versión "posterior", úsela.
Simplemente configura ReSharper para que sugiera lo que realmente quieres que haga .

Siempre tenga en cuenta: ReSharper es una herramienta de refactorización bastante "tonta": no puede reemplazar al desarrollador. Solo puede ayudarlo haciendo un trabajo de copiar y pegar de otra manera estúpido.
Algunas refactorizaciones realizadas por ReSharper resultan incluso en situaciones en las que ReSharper sugiere la refactorización opuesta.

Por lo tanto, no vea las sugerencias de ReSharper como mejores prácticas, sino como posibilidades que podría hacer.

Por cierto: deberías estar motivado por consideraciones de rendimiento aquí. Me sorprendería si hubiera diferencias realmente notables en el rendimiento.


Respuesta corta:

Tiendo a usar la sangría de tal manera que implique que tenga lugar una verdadera lógica de decisión, es decir. Lógica donde se espera más de una posible ruta de ejecución.

Respuesta más larga:

Por lo general, prefiero los bloques con sangría a las declaraciones de "ruptura" anteriores ( continue , break , return o throw ).

Razón: en mi opinión, las declaraciones de ruptura generalmente hacen que el código sea más difícil de leer. Si introduce sangría en el código, es fácil encontrar la ubicación donde ocurre alguna lógica de decisión: esa será la primera línea más adelante en el código que está menos sangrado. Si, en su lugar, usa sentencias de ruptura con una condición invertida, tiene que trabajar más para comprender cómo se ramifica el código y en qué circunstancias se omite cierto código.

Hay una excepción notable para mí, a saber, validar argumentos al comienzo de un método. Formateo este código de la siguiente manera:

if (thisArgument == null) throw new NullArgumentException("thisArgument"); if (thatArgument < 0) throw new ArgumentOutOfRangeException("thatArgument"); ...

Motivo: como no espero que se realicen estas excepciones (es decir, espero que el método se invoque correctamente; la función de llamada es responsable de detectar una entrada no válida, IMO), no quiero sangrar todo el resto del código para algo que no debería pasar.


Como regla general, lo mejor es comenzar siempre los bloques de instrucciones con cualquier condición que lo permita excepto porque reduce la complejidad, pero lo que es más importante, elimina las circunstancias no compatibles antes de seguir adelante, lo que puede aumentar el rendimiento del código y la memoria. Esto también garantiza la seguridad de sus condiciones durante un período de mantenimiento, por lo que es menos probable que se pasen escenarios no válidos al código al que no pertenecen.

Además, creo que el segundo de los dos es más legible personalmente porque no tiene las capas de alcance confundiendo lo que está disponible, es fácil crear una variable en una capa más adelante y no darse cuenta de que no está disponible en otra capa, o tener que Administrarlos para ser modificados apropiadamente etc.

Esto no solo continúa en los bucles, sino que también se refiere a las condiciones de los métodos que deberían regresar; en lugar de tener un método de inicio

if (valid) { do stuff; }

siempre debe comenzar

if (notValid) { return; }


Con el código de estilo continue ; ¿Cómo manejaría una tercera operación que no depende de SomeOtherNestedCondition? Esto hace que el orden del código sea importante, por lo que IMO lo hace menos fácil de mantener.

Por ejemplo:

foreach(....) { if(!SomeCondition) continue; //do some things if(!SomeOtherNestedCondition) continue; //do some further things if(!SomeSecondNonNestedCondition) continue; // do more stuff }

¿Qué sucede cuando SomeOtherNestedCondition provoca la continue; suceder, pero SomeSecondNonNestedCondition aún debe ejecutarse?

Me gustaría refactorizar cada bit de "código" y utilizar anidado if() s para llamar a cada método refactorizado, y mantendría la estructura anidada.


El uso de continue s hace la mayor parte del código en el nivel del código de procedimiento regular. De lo contrario, si hay cinco controles, sangrarás la "carne" de los 10 o 20 caracteres del método, dependiendo del tamaño de la sangría, y esos son caracteres 10/20 que tendrás que desplazarte para ver las líneas más largas.


No debería haber un rendimiento significativo diferente, esto es todo acerca de la legibilidad. Personalmente creo que lo último es más fácil de leer. Menos nidos, más fácil de leer.


No hay diferencia en términos de memoria o rendimiento. El IL subyacente es solo una selección de instrucciones de salto / bifurcación, por lo que realmente no importa si saltan de nuevo a la parte superior del bucle o a la declaración "else".

Debes elegir el que sea más fácil de leer. Personalmente prefiero evitar ''continuar'', pero si tiene muchos niveles de anidamiento, su segundo ejemplo puede ser más fácil de seguir.


Respuesta simple Cualquiera que sea uno es más fácil de leer y entender.


Significado original de continue : el código no se procesará mientras que cualquier condición sea falsa. Aquí hay un ejemplo de la situación:

class Program { static bool SomeCondition = false; static bool SomeOtherNestedCondition = false; static void Main(string[] args) { for (int i = 0; i < 2; i++) { if (SomeCondition) { //do some things if (SomeOtherNestedCondition) { //do some further things } } Console.WriteLine("This text appeared from the first loop."); } for (int i = 0; i < 2; i++) { if (!SomeCondition) continue; //do some things if (!SomeOtherNestedCondition) continue; //do some further things Console.WriteLine("This text appeared from the second loop."); } Console.ReadLine(); } }

Y la salida será:


Usa una combinación de los dos. Yo uso if(condition) continue; y if(condition) return; en la parte superior del bucle para validar el estado actual, y anidado if instrucciones están más abajo para controlar el flujo de lo que estoy tratando de lograr.