2009-05-18 12 views
17

Podría alguien explicarme por qué se considera inadecuadoas tener un try-catch en el método main() para capturar las excepciones no controladas?Por qué son try-catch en main() malo?

[STAThread] 
static void Main() 
{ 
    try 
    { 
     Application.Run(new Form1()); 
    } 
    catch (Exception e) 
    { 
     MessageBox.Show("General error: " + e.ToString()); 
    } 
} 

Tengo entendido que esta es una mala práctica, pero no estoy seguro de por qué.

+2

Es posible que desee mostrar al usuario final algo más informativo que eso, y registrar detalles de la excepción para fines de soporte, pero de lo contrario lo recomendaría como una mejor práctica en lugar de inapropiada. –

+1

Buena pregunta, en realidad. Creo que la respuesta aquí es un poco "sutil". Simplemente llamar a este enfoque "mala práctica" no le hace justicia. – Noldorin

Respuesta

28

No creo que es necesariamente mala práctica. Hay algunas advertencias sin embargo ...

creo que el punto de quien llama esta "mala práctica" era reforzar la idea de que debe ser la captura excepciones más cercano a donde se producen (es decir, como en lo alto de la llamada pila como sea posible/apropiado). Un manejador de excepción general no suele ser una buena idea ya que su reduce drásticamente el flujo de control a su disposición. El manejo de excepciones de grano grueso es bastante importante no una solución razonable para la estabilidad del programa. Desafortunadamente, muchos desarrolladores principiantes piensan que sí, y toman enfoques como esta declaración general de prueba y captura.

decir esto, si que ha utilizado el manejo adecuado (en forma de grano fino y la tarea específica) en el resto de su programa de excepción, y se maneja los errores en consecuencia allí (en lugar de juist mostrar un cuadro de error genérico), luego es probable que sea útil tener un try-catch general para todas las excepciones en el método Main. Un punto a tener en cuenta aquí es que si está reproducible obteniendo errores detectados en este Main try-catch, entonces tiene un error o algo está mal con su manejo de excepciones localizado.

El uso principal de este try-catch con Main sería simplemente para evitar que su programa se bloquee en circunstancias muy inusuales, y debería hacer apenas más que mostrar un mensaje (vagamente) amigable de "error fatal" al usuario, así como posiblemente registrar el error en alguna parte y/o enviar un informe de error. Por lo tanto, para concluir: este método tiene tiene sus usos, pero debe hacerse con gran cuidado, y no por los motivos equivocados.

+1

+1 Probablemente haya una razón diferente para llamarla "mala práctica" de lo que realmente es una mala práctica. –

+1

Estoy de acuerdo con Noldorin en esto. Si tiene un manejo detallado para las excepciones de las que su aplicación puede recuperarse, las excepciones que lo hacen aquí son errores o no son recuperables (a veces, cuando sucede algo malo, no hay nada que pueda hacer al respecto). Utilizaría este controlador de excepción general para intentar registrar algo de información y mostrar un mensaje al usuario (nota: no hay garantía de que pueda iniciar sesión con una excepción grave: es posible que se haya quedado sin memoria o que haya perdido el acceso al disco, etc.) – JMarsch

+0

@JMarsch: Sí, exactamente. Algunos errores muy severos no quedarán atrapados incluso por esto, aunque es útil como un mecanismo de seguridad para los errores que no se ven atrapados durante la prueba (idealmente para ser informados) o para ocurrencias raras y extravagantes. – Noldorin

1

Tienes la excepción all-in que atrapará todo. Entonces, si tienes excepciones no controladas en tu código, nunca las verás.

¡En el lado positivo, su aplicación nunca se bloqueará!

Si se requiere este comportamiento, necesitará tener suficientes registros e informes para que tanto el usuario como usted, como desarrollador, sepan qué sucedió y recuperen o salgan de la forma más elegante posible.

+1

¿No podría el catch-all hacer algo útil con la excepción, p. iniciar sesión, mostrar un cuadro de diálogo de error, levantar una alarma, etc. Luego el programa puede salir con gracia. Parece mejor que simplemente estrellarse – Glen

+0

De ahí mi última oración. – ChrisF

7

No veo cómo es una mala práctica.

Dejar que su programa falle con un error de excepción no controlada no infundirá confianza en sus usuarios finales.

Tal vez alguien podría proporcionar una visión mostrador.

Actualización: Obviamente tendrá que hacer algo útil con la excepción.

  1. registrarla
  2. mostrar al usuario un cuadro de diálogo indicando por qué la aplicación está saliendo (en texto plano, no un StackTrace)
  3. otra cosa que tiene sentido en el contexto de su aplicación.
+0

Un error común que cometen los desarrolladores más nuevos es detectar todas las excepciones. En general, esto es mal visto porque tiene el potencial de enmascarar errores que de otro modo podrían abordarse.Si no puede recuperarse del error en un manejador de excepciones, podría ser mejor dejar que la aplicación falle. Este tipo de errores son más propensos a ser informados por los usuarios finales. Lea este enlace para obtener más información: http://blogs.msdn.com/fxcop/archive/2006/06/14/631923.aspx – senfo

+1

Estoy parcialmente de acuerdo en detectar todas las excepciones en todo el código es malo. Capturar excepciones no controladas en su main y hacer algo con ellas antes de salir no debe considerarse malo. Todo es cuestión de pensar en lo que estás tratando de hacer. El artículo con el que ha establecido un vínculo generalmente es correcto, pero debe tener en cuenta que no trata el caso específico planteado en esta pregunta, que está captando una excepción en main. – Glen

5

No creo que sea una mala práctica en sí misma. Creo que la mala práctica sería si ese fuera el ÚNICO bloque try/catch que tenías en tu aplicación.

3

No estoy seguro, creo que es una mala práctica. Lo que quiere hacer es asegurarse de que la excepción y el estado actual del programa cuando se bloquea termina en manos de un desarrollador, preferiblemente registrado con fecha, hora y el usuario que estaba trabajando con él. Básicamente, debe asegurarse de que su equipo tenga toda la información que necesita para solucionar el problema, independientemente de si el usuario consulta el problema o no. Recuerde que, de hecho, muchos usuarios no se pondrán en contacto con el servicio técnico si se bloquean.

La mala práctica aquí sería atrapar la excepción, mostrando un simple cuadro de diálogo "Error" y cerrando la aplicación. En ese caso, el estado de esa excepción se pierde para siempre.

11

Bueno, este método solo capturará las excepciones lanzadas en su hilo principal. Si utiliza los eventos Application.ThreadException y AppDomian.UnhandledException en su lugar, podrá capturar y registrar todas las excepciones.

+1

Application.ThreadException solo capta excepciones en el hilo de GUI. –

+1

Sí, me acabo de dar cuenta de que una actualización de mi respuesta. Gracias. –

1

Desde el punto de vista de la depuración, esto puede hacer la vida más difícil, ya que hace que cada excepción sea una excepción manejada por el usuario. Esto cambia el comportamiento del depurador, a menos que se rompa con las excepciones no controladas, que potencialmente tienen otros problemas.

Dicho esto, creo que esta es una buena práctica en el momento del lanzamiento. Además, recomiendo escuchar en los eventos AppDomain.UnhandledException y Application.ThreadException, también. Esto le permitirá atrapar aún más excepciones (como algunas excepciones del sistema que no quedarán atrapadas en su controlador "global" más arriba).

Eso le permite registrar los errores y proporcionarle al usuario un mensaje bueno y claro.

0

No estoy diciendo que es una mala práctica, la única cosa que haría diferente, sin embargo es utilizar el construido en caso de que:

 Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException); 

     static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e) 
     { 
      MessageBox.Show(e.Exception.Message); //or do whatever... 
     } 
1

cambiarlo a esto y está bien

catch(Exception ex) 
{ 
    YourLoggingSystem.LogException(ex); 
} 

Por supuesto, esta línea NUNCA debe ser golpeada, ya que tendrás otros manejadores de excepciones en todo tu código que captarán cosas con mucho más contexto.

1

de nivel superior manejo de excepciones es bastante esencial, pero recomiendo usando:

Application.ThreadException += new ThreadExceptionEventHandler(YourExceptionHandlingMethod); 

Sin embargo, esto sólo capturar las excepciones en el hilo de interfaz gráfica de usuario (al igual que su bloque try..catch) - se Debería usar un código similar para cada nueva cadena de caracteres para comenzar a manejar cualquier excepción inesperada de ellos.

Más sobre este tema here.

0

Creo que es una buena práctica tener try..catch en tu main().

Sin embargo, me gustaría hacer algunas modificaciones a su código (para detectar la excepción de registro y, a continuación cuadro de mensaje:.

[STAThread] 
static void Main() 
{ 
    try 
    { 
     Application.Run(new Form1()); 
    } 
    catch (Exception ex) 
    { 
     EventLog log; 
     log = new EventLog("MyApp", Environment.MachineName, "Application"); 

     // write to the event log 
     log.WriteEntry(ex.message, Error); 
     MessageBox.Show("General error");  
    } 
} 
5

Cualquier excepción que se hace a Main() es probable fatal

Si era algo fácil, que debería haber sido tratado más arriba. Si era algo fuera de su control, como OutOfMemoryException, a continuación, el programa debe accidente.

de Windows applicat ion que falla tiene una forma estándar de hacerlo, activan el cuadro de diálogo Windows Error Reporting. (Probablemente lo has visto antes). Puede registrarse para recibir datos de bloqueo cuando esto suceda.

+0

+1 para el diálogo WER –

5

En antigüedad, colocar un try/catch en C++ causaba una penalización de rendimiento bastante pesada, y colocar uno alrededor de main significaba almacenar información de pila adicional para todo, lo que nuevamente era malo para el rendimiento.

Ahora las computadoras son más rápidas, los programadores menos adictos al rendimiento y los tiempos de ejecución están mejor construidos, por lo que ya no es malo (pero aún podría pagar un poco más por ello, no ha evaluado su efecto en años). Por lo tanto, el viejo folclore es como iterar a contrapelo (los compiladores realmente arreglan la iteración de todos modos para usted en la actualidad). En C# está perfectamente bien, pero a alguien le parecerá dudoso hace 10 años.

0

Creo que esto se desaconseja porque las excepciones se detectan solo una vez y puede haber varias cosas, como los hilos de fondo, que necesitan saber si se lanza un proceso.

¿Se trata de una aplicación WinForms? Forms.Application.Run genera eventos cada vez que un hilo arroja una excepción no controlada. Los documentos de MSDN intentan explicar esto, ¡pero el controlador que muestran no funciona! Lea el updated example del sitio de WinForms UE.

0

Si su programa intenta seguir funcionando a pesar de un atrapamiento que sabe qué tipo de violación de las suposiciones abajo, está en una zona de peligro para cosas como explotación remota de fallas de seguridad (desbordamientos de búfer, corrupción de montón) . Ponerlo en un bucle y continuar ejecutando es una gran señal de advertencia para la calidad del software.

Salir lo más rápido posible es lo mejor, p. salida (1). Iniciar sesión y salir es bueno aunque un poco más arriesgado.

¿No me creen? El Mitre Common Weakness Enumeration (CWE) agrees. Estrechamente relacionado es su advice against catching NULL pointer dereferencing de esta manera.