Обработка проблемы необработанных исключений
Я хотел установить некоторый обработчик для всех неожиданных исключений, которые я, возможно, не уловил в своем коде. В Program.Main()
Я использовал следующий код:
AppDomain.CurrentDomain.UnhandledException
+= new UnhandledExceptionEventHandler(ErrorHandler.HandleException);
Но это не сработало, как я ожидал. Когда я запустил приложение в режиме отладки и выдал исключение, оно вызвало обработчик, но после этого в Visual Studio появился помощник исключения, как будто исключение произошло без какой-либо обработки. Я попробовал Application.Exit() внутри обработчика, но он не сработал.
Я хотел бы добиться, чтобы исключение обрабатывалось моим обработчиком, а затем приложение закрывалось. Есть ли другой способ сделать это, или я неправильно использую код выше?
6 ответов
Это потому, что вы запускаете его через Visual Studio в режиме отладки. Если вы выпустите и установите свое приложение где-то еще, ничего, кроме вашего глобального обработчика исключений, не будет обработано.
Обычно я использую что-то подобное, чтобы попытаться поймать все неожиданные исключения верхнего уровня.
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);
}
}
Может быть, это то, что вы считаете полезным? Этот основной код маршрутизирует все три способа перехвата неожиданных исключений верхнего уровня с помощью одного вызова метода. Все, что вам сейчас нужно, это статический класс FatalExceptionHandler
что включает в себя обработку исключений высшего уровня в его Handle
метод.
И действительно, любой разработчик приложений знает, что на самом деле есть только две вещи:
- Показать / записать исключение, как вы считаете нужным
- Убедитесь, что вы выходите / убиваете процесс приложения
Если вы считаете, что второй пункт странный, помните, что мы стараемся делать это в первую очередь только для действительно исключительных ситуаций. Эти вещи, вероятно, являются ошибками, которые нуждаются в изменениях в вашем приложении, чтобы быть точными. Любая другая обработка исключений - функциональная разновидность - должна быть ниже внутри вашего фактического программного кода, перехватывая особые виды исключений, где это имеет смысл, и обрабатывая их там, где это имеет смысл. Все остальное должно пузыриться до вашего FatalExceptionHandler
заявить о себе и остановить работу поврежденной программы из поврежденного состояния
Мертвые программы не лгут...;-)
Обратите внимание, что необработанные исключения все еще довольно фатальны; Вы можете действительно использовать это только для регистрации, или, может быть, какой-нибудь поспешный крупный план. Ни это ни Application.ThreadException
может использоваться как глобальный приемник ошибок.
Лучше всего добавить правильную обработку - например, вокруг всего вашего Main()
логика. Обратите внимание, что даже это не может поймать несколько исключений, таких как ошибки во время загрузки формы (которые становятся особенно неприятными - вы можете поймать их с подключенным отладчиком, но не без).
Такое поведение разработано.
Но есть обходной путь.
Либо ты звонишь Process.GetCurrentProcess().Kill();
в обработчике, или просто не позволяйте обработчику заканчиваться.
Проверьте пример:
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();
}
}
Это не должно быть приемником по умолчанию для исключений, конечно.
Но это должно быть сделано, чтобы изящно сообщать об исключениях.
Примечание: если ваше приложение является приложением Windows Forms, не забудьте:
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
... иначе приложение завершится, даже если вы обработаете исключения с помощью обработчиков, указанных в других ответах.