Обработка проблемы необработанных исключений - PullRequest
36 голосов
/ 02 января 2009

Я хотел установить какой-нибудь обработчик для всех непредвиденных исключений, которые я, возможно, не уловил внутри своего кода. В Program.Main() я использовал следующий код:

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

Но это не сработало, как я ожидал. Когда я запустил приложение в режиме отладки и выдал исключение, оно вызвало обработчик, но после этого в Visual Studio появился помощник исключения, как будто исключение возникло без какой-либо обработки. Я попробовал Application.Exit () внутри обработчика, но он тоже не сработал.

Чего я хотел бы добиться, так это того, чтобы исключение обрабатывалось моим обработчиком, а затем приложение красиво закрывалось. Есть ли другой способ сделать это, или я неправильно использую код выше?

Ответы [ 5 ]

34 голосов
/ 02 января 2009

Обычно я использую что-то подобное, чтобы попытаться перехватить все неожиданные исключения верхнего уровня.

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.

И действительно, любой разработчик приложений знает, что на самом деле есть только две вещи:

  1. Показать / записать исключение, как вы считаете нужным
  2. Убедитесь, что вы завершили / убили процесс приложения

Если вы считаете, что второй пункт является странным, помните, что мы стараемся делать это в первую очередь только для действительно исключительных ситуаций. Эти вещи, вероятно, являются ошибками, которые нуждаются в изменениях в вашем приложении, чтобы быть точно исправленными. Любая другая обработка исключений - функциональная разновидность - должна быть ниже внутри вашего фактического программного кода, перехватывая особые виды исключений, где это имеет смысл, и обрабатывая их там, где это имеет смысл. Все остальное должно всплыть на вашем FatalExceptionHandler, чтобы заявить о себе и остановить работу поврежденной программы из поврежденного состояния

Мертвые программы не лгут ...; -)

29 голосов
/ 02 января 2009

Это потому, что вы запускаете его через Visual Studio в режиме отладки. Если вы выпустите и установите свое приложение где-то еще, ничего, кроме вашего глобального обработчика исключений, не будет обработано.

8 голосов
/ 02 января 2009

Обратите внимание, что необработанные исключения все еще довольно фатальны; Вы можете использовать это только для регистрации, или, может быть, какой-нибудь поспешный крупный план. Ни это, ни Application.ThreadException не могут использоваться в качестве глобального приемника ошибок.

Лучший подход - добавить правильную обработку - например, вокруг всей логики Main(). Обратите внимание, что даже this не может поймать несколько исключений, таких как ошибки во время загрузки формы (которые становятся особенно неприятными - вы можете ловить их с подключенным отладчиком, но не без).

2 голосов
/ 08 марта 2009

Возможно, то, что вы ищете, это Environment.Exit(int errorcode)

0 голосов
/ 29 июня 2009

Такое поведение задуманно.

Но там есть обходной путь.

Либо вы вызываете 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();
    }
}

Конечно, это не должен быть приемник по умолчанию для исключений.

Но это нужно сделать, чтобы изящно сообщать об исключениях.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...