2009-01-02 12 views
34

Quería configurar algún controlador para todas las excepciones inesperadas que podría no haber detectado dentro de mi código. En Program.Main() He utilizado el siguiente código:Manejo del problema de excepciones no controladas

AppDomain.CurrentDomain.UnhandledException 
    += new UnhandledExceptionEventHandler(ErrorHandler.HandleException); 

Pero no funcionó como esperaba. Cuando inicié la aplicación en modo de depuración y lancé una excepción, llamó al controlador, pero luego apareció el asistente de excepción en Visual Studio como si la excepción se hubiera producido sin ningún tipo de manipulación. Intenté Application.Exit() dentro del controlador pero no funcionó tan bien.

Lo que me gustaría lograr es que la excepción se maneje con mi controlador y luego la aplicación se cierra correctamente. ¿Hay alguna otra forma de hacerlo o estoy usando el código anterior de la manera incorrecta?

Respuesta

27

Es porque lo está ejecutando a través de Visual Studio en modo de depuración. Si libera e instala su aplicación en otro lugar, solo se procesará su manejador global de excepciones.

6

Tenga en cuenta que las excepciones no controladas siguen siendo bastante fatales; solo puedes utilizar esto para iniciar sesión, o tal vez un cierre apresurado. Ni esto ni Application.ThreadException se pueden usar como sumidero global para errores.

El mejor enfoque es agregar un manejo adecuado, por ejemplo, alrededor de toda su lógica Main(). Tenga en cuenta que incluso este no puede detectar algunas excepciones, como los errores durante la carga de formulario (que se vuelven especialmente desagradables: puede atraparlos con un depurador adjunto, pero no sin).

+0

bueno, sí, por supuesto que lo sé;) – agnieszka

+0

¿por qué no cogerlos en Main()? –

+0

"sé que" fue una respuesta a la parte "sumidero de errores". me enseñaron try-catch en main es algo que no debes hacer. sin embargo, debo decir honestamente que no sé por qué sería un mal enfoque (por supuesto si atrapo todas las excepciones que puedo pensar dentro del código) – agnieszka

31

Normalmente utilizo algo así para tratar de detectar todas las excepciones de alto nivel inesperadas.

using System; 

static class Program 
{ 
    [STAThread] 
    static void Main(string[] argv) 
    { 
    try 
    { 
     AppDomain.CurrentDomain.UnhandledException += (sender,e) 
     => FatalExceptionObject(e.ExceptionObject); 

     Application.ThreadException += (sender,e) 
     => FatalExceptionHandler.Handle(e.Exception); 

     // whatever you need/want here 

     Application.Run(new MainWindow()); 
    } 
    catch (Exception huh) 
    { 
     FatalExceptionHandler.Handle(huh); 
    } 
    } 

    static void FatalExceptionObject(object exceptionObject) { 
    var huh = exceptionObject as Exception; 
    if (huh == null) { 
     huh = new NotSupportedException(
     "Unhandled exception doesn't derive from System.Exception: " 
     + exceptionObject.ToString() 
    ); 
    } 
    FatalExceptionHandler.Handle(huh); 
    } 
} 

¿Es posible que también encuentre algo útil? Este código principal enruta las tres formas de atrapar excepciones inesperadas de alto nivel a través de una llamada a un método. Todo lo que necesita ahora es una clase estática FatalExceptionHandler que incluye el manejo de excepciones de nivel superior en su método Handle.

Y en realidad, cualquier desarrollador de aplicaciones sabe en realidad hay sólo dos cosas que hacer allí:

  1. Mostrar/log excepción como mejor le parezca
  2. Asegúrese de que el proceso de salida/matar a la aplicación

Si cree que el elemento dos es extraño, recuerde que solo nos molestamos en hacer esto en primer lugar para situaciones realmente excepcionales. Estas cosas probablemente son errores que necesitan cambios en su aplicación para ser tratados con precisión. Cualquier otro manejo de excepciones, el tipo funcional, debe estar más abajo dentro de su código de programa real, captando tipos específicos de excepciones donde esto tenga sentido y manipularlas allí de la manera que tenga sentido. Todo lo demás debe tener burbujas hasta su FatalExceptionHandler a darse a conocer y detener el programa, posiblemente, lisiado de trabajo de un estado corrupto

programas muertos no cuentan mentiras ... ;-)

+0

+1 para los programas Dead no dicen mentiras ... ;-) –

+1

Como puede ver en este [¿Por qué UnhandledExceptionEventArgs.ExceptionObject es un objeto y no una excepción?] (Http://stackoverflow.com/questions/913472/why-is-unhandledexceptioneventargs-exceptionobject-an-object-and-not- an-exception) post, * puede * no ser prudente lanzar 'e.ExceptionObject' a' Exception' sin una comprobación primero, ya que no siempre será del tipo 'Exception' ... podría terminar creando un' nuevo ' Excepción' aquí. – Sheridan

+0

Me pregunté por qué era un objeto, pero nunca lo analicé. Aprendí algo nuevo hoy. ¡Gracias! Cambiará la respuesta para tratar de remediar esto. – peSHIr

2

Tal vez lo que estás buscando es Environment.Exit(int errorcode)

1

Ese comportamiento es por diseño.

Pero no es un work-around.

O llama al Process.GetCurrentProcess().Kill(); dentro del controlador, o simplemente no deja que el manejador finalice.

Salida del ejemplo:

class Program 
{ 
    void Run() 
    { 
     AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException); 

     Console.WriteLine("Press enter to exit."); 

     do 
     { 
      (new Thread(delegate() 
      { 
       throw new ArgumentException("ha-ha"); 
      })).Start(); 

     } while (Console.ReadLine().Trim().ToLowerInvariant() == "x"); 


     Console.WriteLine("last good-bye"); 
    } 

    int r = 0; 

    void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) 
    { 
     Interlocked.Increment(ref r); 
     Console.WriteLine("handled. {0}", r); 
     Console.WriteLine("Terminating " + e.IsTerminating.ToString()); 

     Thread.CurrentThread.IsBackground = true; 
     Thread.CurrentThread.Name = "Dead thread";    

     while (true) 
      Thread.Sleep(TimeSpan.FromHours(1)); 
     //Process.GetCurrentProcess().Kill(); 
    } 

    static void Main(string[] args) 
    { 
     Console.WriteLine("..."); 
     (new Program()).Run(); 
    } 
} 

Esto no debería ser un sumidero por defecto para las excepciones, sin duda.

Pero esto se debe hacer para informar las excepciones correctamente.

Cuestiones relacionadas