¿Alguien todavía usa [goto] en C # y si es así por qué? [cerrado]

104

Me preguntaba si alguien todavía usa la sintaxis de la palabra clave "goto" en C # y qué posibles razones existen para hacerlo.

Tiendo a ver cualquier declaración que haga que el lector salte el código como una mala práctica, pero me preguntaba si había escenarios creíbles para usar tal sintaxis.

Ir a definición de palabra clave

Brian Scott
fuente
3
¿Qué quieres decir con "todavía"? ¿Hubo un período de tiempo que la gente lo usó todo el tiempo [en c #]?
Macizo
4
@Massif: "still" tenía la intención de enfatizar la opinión moderna sobre el uso de "goto" como preludio al código espagueti y la falta de legibilidad en el código fuente. Muy rara vez ve ejemplos de código que incluyan esta palabra clave en particular, por lo que estaba interesado en preguntar en primer lugar.
Brian Scott
50
Si el lector "salta" el código es una mala práctica, ¿también evita "romper", "continuar", "lanzar" y "regresar"? Todos provocan una rama en el flujo de control, a veces una rama no local. "Throw" ni siquiera te dice adónde va, a diferencia de goto.
Eric Lippert
2
Solía gotoromper un bucle y volver a la declaración inicial de acuerdo con una condición específica
Nitin Sawant
3
Me gusta goto. Traté de evitarlo debido a la tendencia de la gente que dice que lo evite porque dificulta la lectura del código. Habiendo aprendido el lenguaje ensamblador y las declaraciones de rama, creo que a veces, puede hacer que el código sea más legible. Creo que múltiples usos en un método y saltar demasiado hacia abajo en el código puede hacer más daño que bien. Pero si está pensando que un goto funcionaría bien aquí, un simple goto de vez en cuando no debería hacer que salga de su camino para evitarlo solo porque el consenso común es evitarlo.
eaglei22

Respuestas:

93

Hay algunos casos (raros) en los que goto puede mejorar la legibilidad. De hecho, la documentación a la que vinculó enumera dos ejemplos:

Un uso común de goto es transferir el control a una etiqueta de caja de interruptor específica o la etiqueta predeterminada en una declaración de interruptor.

La instrucción goto también es útil para salir de bucles profundamente anidados.

Aquí hay un ejemplo para el último:

for (...) {
    for (...) {
        ...
        if (something)
            goto end_of_loop;
    }
}

end_of_loop:

Por supuesto, también hay otras formas de solucionar este problema, como refactorizar el código en una función, usar un bloque ficticio a su alrededor, etc. (consulte esta pregunta para obtener más detalles). Como nota al margen, los diseñadores del lenguaje Java decidieron prohibir goto por completo e introducir una declaración de ruptura etiquetada en su lugar.

Heinzi
fuente
48
Normalmente, trataría de refactorizar esto para poner los bucles en un método separado del que podría regresar ...
Jon Skeet
2
@Heinzi - No he visto que se justifique el goto. Como dice Jon, si está "justificado", el código está pidiendo ser refactorizado.
manojlds
29
rotulado etiquetado, solo una forma más larga de decir goto porque hace lo mismo maldito ....
Jesús Ramos
20
@Jesus, pero luego con goto, puedes ir a cualquier parte. La rotura etiquetada garantiza que se salga del circuito.
mihsathe
1
A menos que esté siendo aventurero y use goto con una dirección (lo he visto antes), ese problema se mitigará. Y dudo que alguien esté usando ganchos de desvío en su código C # y Java para explotar las declaraciones goto.
Jesus Ramos
66

Recuerdo esta parte

switch (a)     
{ 
    case 3: 
        b = 7;
        // We want to drop through into case 4, but C# doesn't let us
    case 4: 
        c = 3;
        break; 
    default: 
        b = 2;
        c = 4;
        break; 
}

A algo como esto

switch (a)     
{
    case 3: 
        b = 7;
        goto case 4;    
    case 4: 
        c = 3;
        break;     
    default: 
        b = 2;
        c = 4;
        break;
}

Refiera esto

V4Vendetta
fuente
17
De hecho, veo esta como la razón más válida para usar [goto] hasta ahora. Al menos en este escenario, aumenta la legibilidad para los programadores que no saben que los casos se encuentran entre sí sin una declaración de interrupción.
Brian Scott
11
@Brian Scott, V4Vendetta. A menos que me equivoque, la primera declaración no se compila en C #. Eso ayudaría a la comprensión del programador.
Jodrell
2
V4Vendetta, ¿por qué insertó un salto en el primer fragmento de código ...? Era mejor mostrarlo sin interrupciones, de lo contrario, los dos fragmentos hacen cosas diferentes. La razón por la que necesita el goto en el segundo ejemplo es precisamente porque el primero no se compila en C # (como lo haría en C).
Stephen Holt
23

Lo uso extensamente en Eduasync para mostrar el tipo de código que el compilador genera para usted cuando usa métodos asíncronos en C # 5. Vería lo mismo en bloques iteradores.

Sin embargo, en el código "normal", no recuerdo la última vez que lo usé ...

Jon Skeet
fuente
1
¿Puede proporcionar un pequeño ejemplo de por qué se prefirió este enfoque o fue simplemente una preferencia personal?
Brian Scott
1
@Brian: No está muy claro a qué te refieres. Eduasync muestra el código C # equivalente a lo que el compilador hace por usted, y genera código que usa goto, efectivamente ...
Jon Skeet
9

goto es genial para romper muchos bucles donde break no funcionaría bien (digamos en condiciones de error), y como Kragen dijo, el compilador usa goto para generar declaraciones de cambio y algunas otras cosas también.

Jesús Ramos
fuente
7
Seguramente "romper" / "continuar" son mejores enfoques para la gestión de bucles en lugar de requerir que el editor de código salte el código fuente tratando de entender dónde ocurre el siguiente paso.
Brian Scott
6
No si tiene bucles anidados.
Jesús Ramos
1
ok, puedo ver esto como un escenario válido.
Brian Scott
1
En una condición de error, debería considerar lanzar una excepción.
Jodrell
6
Si desea manejar el error internamente sin una excepción, esta sería una forma válida de hacerlo.
Jesús Ramos
8

No recuerdo haber usado nunca goto. Pero tal vez mejore la intención de un bucle para siempre del que realmente nunca querrás salir (no break, pero aún puedes returno throw):

forever: {
  // ...
  goto forever;
}

Por otra parte, un simple while (true)debería ser suficiente ...

Además, puede usarlo en una situación en la que desee que la primera iteración de un bucle comience en el medio del bucle: busque aquí un ejemplo.

Jordão
fuente
La respuesta vinculada contiene un uso "interesante" de goto.. y while(true) {..}no es un uso interesante ..
user2864740
5

El compilador usa gotodeclaraciones en varias piezas de código generado, por ejemplo, en tipos de bloques de iteradores generados (generados cuando se usa la yield returnpalabra clave; estoy bastante seguro de que los tipos de serialización XML generados también tienen algunas gotodeclaraciones allí en algún lugar también.

Consulte Detalles de implementación del bloque Iterator: máquinas de estado generadas automáticamente para obtener más detalles sobre por qué / cómo el compilador de C # maneja esto.

Aparte del código generado, no hay una buena razón para usar una gotodeclaración en el código normal; hace que el código sea más difícil de entender y, como resultado, más propenso a errores. Por otro lado, usar gotodeclaraciones en el código generado como este puede simplificar el proceso de generación y normalmente está bien porque nadie va a leer (o modificar) el código generado y no hay posibilidad de que se cometan errores porque una máquina está escribiendo.

Vea la declaración Go-to considerada dañina para un argumento en contra goto, así como una pieza clásica de la historia de la programación.

Justin
fuente
4
Esto es estúpido: hay varios casos en los que goto es útil, como lo ilustran otras respuestas. O los frota explícitamente, o simplemente decir "está mal" es, bueno, incorrecto.
o0 '.
@ Lohoris No me lo creo: todos los ejemplos que he visto en los que goto "mejora la legibilidad" (incluidas las respuestas aquí) serían mucho más legibles después de una simple refactorización.
Justin
3
@Justin no, a veces los bucles anidados son solo la forma más natural de hacer algo, por ejemplo, si está atravesando una matriz de matrices.
o0 '.
6
@Justin no siempre es más claro tenerlo en una función. Estás forzando algo (teniendo una función) solo para evitar algo que odias religiosamente (usando un goto). Indicación clara de haber hecho algo mal.
o0 '.
3
Las llamadas de @Justin Functions tienen gastos generales. gotono. Algo a considerar.
Dan Bechard
2

El procesador implementa al menos una instrucción de salto y estoy seguro de que muchas declaraciones las usan en su implementación o interpretación.

Una de las cosas buenas de usar un lenguaje de tercera o cuarta generación es que estos detalles físicos se abstraen de nosotros. Si bien deberíamos tener en cuenta la ley de la abstracción con fugas , creo que también deberíamos usar nuestras herramientas como están diseñadas (lo siento ). Si estuviera escribiendo código y me gotopareciera una buena idea, sería hora de refactorizar. El propósito de un lenguaje estructurado es evitar estos "saltos" y crear un flujo lógico en nuestra ingeniería.

Debería evitar el uso de, breakpero no puedo pasar por alto el beneficio de rendimiento. Sin embargo, si tengo bucles anidados que se necesitan mutuamente break, es hora de refactorizar.

Si alguien puede proponer un uso de gotoeso que parece mejor que refactorizar, con mucho gusto retiraré mi respuesta.

Espero no ser culpable de correr al " cobertizo de bicicletas " aquí. Como dice Kragen, lo que es lo suficientemente bueno para Dijkstra es lo suficientemente bueno para mí.

Jodrell
fuente
1
Tomando un dynamicobjeto y caminando por su gráfico de objetos que contiene varios diccionarios para llegar a los valores que necesito. No tiene sentido usar métodos que tienen un parámetro de dynamicesperar una forma de objeto exacta. Con goto para romper varias capas y continuar caminando a través de una colección de estos objetos. [No soy dueño de los tipos, así que no puedo proporcionar un mejor acceso, así que la reflexión o la dinámica son]
Chris Marisic
-6

Goto nunca es mejor. Y continuar, romper (excepto en caso de cambio / caso), retorno (múltiple) y lanzamiento también deben mantenerse al mínimo. Nunca querrás escapar del medio de los bucles del nido. Siempre quiere que las sentencias de control de bucle tengan todo el control de bucle. La sangría tiene información, y todas estas declaraciones desechan esa información. También puede quitar todas las sangrías.

Kirk Augustin
fuente
10
Querría salir de un ciclo si no tiene sentido mantener la ejecución del ciclo. De lo contrario, terminará perdiendo más tiempo de procesamiento en bucles más largos sin ningún motivo.
Skuld
12
@ Kirk, ¿esto suena más a una opinión que a algo cuantitativo?
Brian Scott