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