documentacion - param name c#
Ir a la declaraciĆ³n considerado daƱino? (15)
Si la afirmación anterior es correcta, ¿por qué cuando uso el reflector en .Net BCL veo que se usa mucho?
EDITAR: déjeme reformular: ¿todos los GO-TO que veo en el reflector están escritos por humanos o compiladores?
goto
considerado dañino (para uso humano pero para computadoras está bien).
porque no importa cuán locamente usemos (humano) goto
, el compilador siempre sabe cómo leer el código.
Créame...
Leer el código de otros con goto
s es DIFÍCIL.
Leer tu propio código con goto
s es más difícil.
Es por eso que lo ves usado en nivel bajo (lenguajes de máquina) y no en nivel alto (lenguajes humanos, por ejemplo, C #, Python ...);)
"C proporciona la instrucción goto de uso indebido y las etiquetas a las que se debe derivar. Formalmente, el goto nunca es necesario y, en la práctica, casi siempre es fácil escribir código sin él. No hemos utilizado goto en este libro".
- K&R (2ª ed.): Página 65
¿Qué pasa con un bucle doble o muchos bucles anidados, de los que ha salido, por ejemplo?
foreach (KeyValuePair<DateTime, ChangedValues> changedValForDate in _changedValForDates)
{
foreach (KeyValuePair<string, int> TypVal in changedValForDate.Value.TypeVales)
{
RefreshProgress("Daten werden geändert...", count++, false);
if (IsProgressCanceled)
{
goto TheEnd; //I like goto :)
}
}
}
TheEnd:
En este caso, debe considerar que aquí se debe hacer lo siguiente con un descanso:
foreach(KeyValuePair<DateTime, ChangedValues> changedValForDate in _changedValForDates)
{
foreach (KeyValuePair<string, int> TypVal in changedValForDate.Value.TypeVales)
{
RefreshProgress("Daten werden geändert...", count++, false);
if (IsProgressCanceled)
{
break; //I miss goto :|
}
}
if (IsProgressCanceled)
{
break; //I really miss goto now :|
}//waaaAA !! so many brakets, I hate''m
}
A veces uso goto cuando quiero realizar una acción de terminación:
static void DoAction(params int[] args)
{
foreach (int arg in args)
{
Console.WriteLine(arg);
if (arg == 93) goto exit;
}
//edit:
if (args.Length > 3) goto exit;
//Do another gazillion actions you might wanna skip.
//etc.
//etc.
exit:
Console.Write("Delete resource or whatever");
}
Entonces, en lugar de golpear el return
, lo envío a la última línea que realiza otra acción final a la que puedo referirme desde varios lugares en el fragmento en lugar de simplemente terminar.
Creo que el siguiente extracto del artículo de Wikipedia sobre Goto es particularmente relevante aquí:
Probablemente la crítica más famosa de GOTO es una carta de 1968 de Edsger Dijkstra llamada Ir a una declaración considerada perjudicial. En esa carta, Dijkstra argumentó que las declaraciones GOTO sin restricciones deberían eliminarse de los lenguajes de nivel superior porque complicaban la tarea de analizar y verificar la corrección de los programas (en particular los que involucran bucles). Se presenta un punto de vista alternativo en la Programación estructurada de Donald Knuth con ir a Declaraciones que analiza muchas tareas de programación comunes y encuentra que, en algunas de ellas, GOTO es el constructo de lenguaje óptimo para usar.
Entonces, por un lado, tenemos a Edsger Dijkstra (un científico informático increíblemente talentoso) que discute el uso de la declaración GOTO
, y específicamente que discute el uso excesivo de la declaración GOTO
debido a que es una forma mucho menos estructurada de escribir. código.
Por otro lado, tenemos a Donald Knuth (otro científico informático increíblemente talentoso) que sostiene que usar GOTO
, especialmente usarlo de manera juiciosa, puede ser realmente el "mejor" y el constructo más óptimo para una determinada pieza de código de programa.
En última instancia, en mi humilde opinión, creo que ambos hombres tienen razón. Dijkstra tiene razón al decir que el uso excesivo de la declaración GOTO
hace que una parte del código sea menos legible y menos estructurada, y esto es ciertamente cierto cuando se ve la programación de computadoras desde una perspectiva puramente teórica.
Sin embargo, Knuth también tiene razón, ya que, en el "mundo real", donde uno debe adoptar un enfoque pragmático , la declaración GOTO
, cuando se usa sabiamente, puede ser la mejor opción de construcción de lenguaje para usar.
Cuando se compila hasta el código de ensamblaje, todos los controles se estructuran y se convierten en (no) saltos condicionales. Sin embargo, el optimizador puede ser demasiado poderoso, y cuando el desensamblador no puede identificar a qué estructura de control corresponde un patrón de salto, la declaración siempre correcta, es decir, goto label;
será emitido.
Esto no tiene nada que ver con el daño (total) de goto
.
En el código descompilado, virtualmente todos los goto
que veas serán sintéticos. No te preocupes por ellos; son un artefacto de cómo se representa el código en el nivel bajo.
¿En cuanto a razones válidas para ponerlas en tu propio código? El principal que se me ocurre es que el lenguaje que está utilizando no proporciona una construcción de control adecuada para el problema que está abordando; los idiomas que facilitan la tarea de hacer que los sistemas de control de flujo personalizados no tengan goto
en absoluto. También siempre es posible evitar usarlos, pero reorganizar el código arbitrariamente complejo en un bucle while y un montón de condicionales con una batería completa de variables de control ... que pueden hacer que el código sea aún más oscuro (y más lento también; los compiladores generalmente no son lo suficientemente inteligentes como para separar tal complejidad). El objetivo principal de la programación debe ser producir una descripción de un programa que sea claro tanto para la computadora como para la gente que lo está leyendo.
Estos goto
son generados muy a menudo por el compilador, especialmente dentro de los enumeradores. El compilador siempre sabe lo que está haciendo.
Si se encuentra en la necesidad de utilizar goto
, debe asegurarse de que sea la única opción. Muy a menudo encontrará que hay una mejor solución.
Aparte de eso, hay muy pocos casos en que se pueda justificar el uso de goto
, como cuando se usan bucles anidados. De nuevo, todavía hay otras opciones en este caso. Podría romper el bucle interno en una función y usar una declaración de retorno en su lugar. Debe observar detenidamente si la llamada al método adicional es realmente demasiado costosa.
En respuesta a su edición:
No, no todos los gotos son generados por compiladores, pero muchos de ellos son el resultado de las máquinas de estado generadas por compiladores (enumeradores), conmutación de declaraciones de casos u optimizadas si las estructuras se basan. Solo hay unos pocos casos en los que podrás juzgar si fue el compilador o el desarrollador original. Puede obtener una buena sugerencia al observar la función / nombre de la clase, un compilador generará nombres "prohibidos" para evitar conflictos de nombres con su código. Si todo parece normal y el código no se ha optimizado u ofuscado, probablemente se intente utilizar goto.
Estos compases son generados muy a menudo por el compilador, especialmente dentro de los enumeradores. El compilador siempre sabe lo que está haciendo.
Si se encuentra en la necesidad de utilizar goto, debe asegurarse de que sea la única opción. Muy a menudo encontrará que hay una mejor solución.
Aparte de eso, hay muy pocos casos en que se pueda justificar el uso de goto, como cuando se usan bucles anidados. De nuevo, todavía hay otras opciones en este caso. Podría romper el bucle interno en una función y usar una declaración de retorno en su lugar. Debe observar detenidamente si la llamada al método adicional es realmente demasiado costosa.
GOTO puede ser útil, si no se usa en exceso como se indicó anteriormente. Microsoft incluso lo usa en varios casos dentro del propio .NET Framework.
La regla general es que no necesitas usar goto
. Como con cualquier regla, por supuesto hay excepciones, pero como con cualquier excepción son pocas.
El comando goto
es como una droga. Si se usa en cantidades limitadas solo en situaciones especiales, es bueno. Si usas demasiado todo el tiempo, arruinará tu vida.
Cuando está perdiendo el código usando Reflector, no está viendo el código real. Está viendo el código que se recrea a partir de lo que el compilador produjo a partir del código original. Cuando ves un goto
en el código recreado, no es seguro que haya un goto
en el código original. Puede haber un comando más estructurado para controlar el flujo, como una break
o una continue
que haya sido implementado por el compilador de la misma manera que un goto
, de modo que Reflector no pueda notar la diferencia.
Lo anterior no es realmente correcto: era un dispositivo polémico utilizado por Dijkstra en un momento en que los gotos eran casi la única estructura de control de flujo en uso. De hecho, varias personas han producido refutaciones, incluido el papel clásico de Knuth "Programación estructurada usando Goto" (título de memoria). Y hay algunas situaciones (manejo de errores, máquinas de estados) donde los gotos pueden producir un código más claro (IMHO) que las alternativas "estructuradas".
Si es perjudicial o no, es una cuestión de gustos y disgustos de cada uno. Personalmente no me gustan, y los encuentro muy improductivos ya que intentan mantener el código.
Ahora, una cosa es cómo los gotos afectan nuestra lectura del código, mientras que otra es cómo se realiza el jitter cuando se encuentra uno. Del blog de Eric Lippert , me gustaría citar:
Primero ejecutamos un pase para transformar bucles en gotos y etiquetas.
Entonces, de hecho, el compilador transforma bastante cada estructura de control de flujo en un patrón de goto / etiqueta mientras emite IL. Cuando el reflector lee el IL del conjunto, reconoce el patrón y lo transforma de nuevo a la estructura de control de flujo apropiada.
En algunos casos, cuando el código emitido es demasiado complicado para que el reflector lo entienda, solo muestra el código C # que usa etiquetas y fotos, equivalente al IL que está leyendo. Este es el caso, por ejemplo, cuando se implementan los IEnumerable<T>
con yield return
y yield break
. Este tipo de métodos se transforman en sus propias clases implementando la IEnumerable<T>
utilizando una máquina de estado subyacente. Creo que en BCL encontrarás muchos de estos casos.
Tenga en cuenta que el código que está viendo en Reflector es un desensamblaje: Reflector está mirando los códigos de bytes compilados e intenta juntar el código fuente original.
Con eso, debes recordar que las reglas contra los goto
s se aplican al código de alto nivel. Todas las construcciones que se utilizan para reemplazar goto
s ( for
, while
, break
, switch
, etc.) se compilan en código utilizando JMPs.
Entonces, Reflector mira el código de esta manera:
A:
if !(a > b)
goto B;
DoStuff();
goto A;
B: ...
Y debe darse cuenta de que en realidad fue codificado como:
while (a > b)
DoStuff();
A veces, el código que se lee es demasiado complicado para que reconozca el patrón.
Go To
declaración en sí no es perjudicial, incluso es bastante útil a veces. Dañino son los usuarios que tienden a ponerlo en lugares inadecuados en su código.