Lidando com o problema de exceções não tratadas

Eu queria definir algum manipulador para todas as exceções inesperadas que eu não poderia ter pego dentro do meu código. Em Program.Main() usei o seguinte código:

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

Mas não funcionou como eu esperava. Quando iniciei o aplicativo no modo de debugging e lancei uma exceção, ele chamou o manipulador, mas depois o auxiliar de exceção no Visual Studio apareceu como se a exceção tivesse ocorrido sem qualquer manipulação. Eu tentei Application.Exit () dentro do manipulador, mas não funcionou tão bem.

O que eu gostaria de alcançar é que a exceção é tratada com meu manipulador e, em seguida, o aplicativo fecha bem. Existe alguma outra maneira de fazer isso ou estou usando o código acima da maneira errada?

É porque você está usando o Visual Studio no modo de debugging. Se você liberar e instalar seu aplicativo em outro local, apenas o manipulador de exceção global será processado.

Normalmente eu uso algo assim para tentar capturar todas as exceções de nível superior 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); } } 

Talvez seja algo que você acha útil também? Esse código principal direciona todas as três maneiras de capturar exceções de nível superior inesperadas por meio de uma chamada de método. Tudo o que você precisa agora é de uma class estática FatalExceptionHandler que inclua seu tratamento de exceção de nível superior em seu método Handle .

E realmente, qualquer desenvolvedor de aplicativos sabe que há apenas duas coisas para fazer lá:

  1. Mostrar / registrar a exceção como você vê
  2. Certifique-se de sair / matar o processo de inscrição

Se você acha que o item dois é estranho, lembre-se de que só nos preocupamos em fazer isso em primeiro lugar para situações realmente excepcionais. Essas coisas provavelmente são bugs que precisam de alterações no seu aplicativo para serem tratadas com precisão. Qualquer outro tratamento de exceção – o tipo funcional – deve ser mais baixo dentro do seu código de programa real, pegando tipos específicos de exceções onde isso faz sentido e lidando com eles da maneira que faz sentido. Qualquer outra coisa deve aparecer no seu FatalExceptionHandler para se tornar conhecida e impedir que o programa possivelmente danificado funcione a partir de um estado corrompido

Programas mortos não contam mentiras … 😉

Observe que as exceções não tratadas ainda são bastante fatais; você só pode realmente usar isso para registrar, ou talvez algum fechamento apressado. Nem isso nem Application.ThreadException podem ser usados ​​como um coletor global para erros.

A melhor abordagem é adicionar um tratamento adequado – por exemplo, em torno de toda a sua lógica Main() . Note que mesmo isso não pode pegar algumas exceções, como erros durante o carregamento do formulário (o que é particularmente desagradável – você pode pegá-los com um depurador anexado, mas não sem).

Talvez o que você esteja procurando seja Environment.Exit(int errorcode)

Esse comportamento é por design.

Mas há uma solução alternativa.

Ou você chama Process.GetCurrentProcess().Kill(); dentro do manipulador, ou simplesmente não deixe o manipulador terminar.

Confira o exemplo:

 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(); } } 

Isso não deve ser um coletor padrão para exceções, certamente.

Mas isso deve ser feito para relatar as exceções normalmente.