Почему исключения AppDomain неизменно завершают работу приложения? - PullRequest
7 голосов
/ 19 августа 2009

Это относится к предыдущему вопросу .

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

Для справки см. этот пример .

Самое главное, что я хотел бы иметь в этом случае, это «тихо» прекратить процесс - без отображения диалогового окна Windows, которое спрашивает, хочу ли я отправить отчет об ошибке или нет.

Это мой AppDomain UnhandledExceptionHandler:

private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{            
    try
    {
        // Maybe do some logging here if allowed
    }
    catch
    {
    }

    // then just terminate the application
    Application.Exit();            
}

UPDATE
В свете комментариев в этого ответа я хотел бы уточнить, что наиболее важно, я хотел бы узнать больше о механизме, который позволяет потоку пользовательского интерфейса иметь раннюю возможность ловить необработанные исключения через Application.ThreadException механизм. И может ли такое поведение быть реализовано в потоке без пользовательского интерфейса.

Ответы [ 3 ]

8 голосов
/ 19 августа 2009

После еще нескольких поисков в Google я нашел это очень интересное объяснение, которое было дано той же самой проблеме, как описано Джеффом Этвудом в его блоге .

Привет всем, Извините за путаницу. Это поведение на самом деле дизайн, хотя дизайн может быть немного запутанным время от времени.

Первое, что нужно понять, это то, что событие UnhandledException не является обработчиком необработанного исключения. Регистрация на событие, вопреки тому, что написано в документации :-(, не приводит к обработке необработанных исключений. (С тех пор они не будут обрабатываться, но я остановлюсь на циклическом рассуждении уже ...) Событие UnhandledException просто уведомляет вас о том, что исключение прошло необработанным , на случай, если вы хотите попытаться сохранить состояние до того, как ваш поток или приложение умрут. FWIW, я подал ошибку, чтобы получить документы неподвижная.

Просто, чтобы усложнить ситуацию, в v1.0 и 1.1 необработанное исключение не всегда означало, что ваше приложение умрет. Если необработанное исключение возникло в чем-либо кроме основного потока или потока, который начал свою жизнь в неуправляемом коде, CLR съел исключение и позволил вашему приложению продолжать работу. Как правило, это было зло, потому что часто случалось так, что потоки ThreadPool молча отмирали один за другим, пока ваше приложение фактически не выполняло никакой работы. Выяснить причину такого рода неудач было практически невозможно. Возможно, поэтому Джефф думал, что это сработало раньше ... он просто всегда видел сбои в неосновных потоках.

В версии 2.0 необработанное исключение в любом потоке приведет к удалению приложения. Мы обнаружили, что отладку сбоев намного проще, чем отладку зависаний или проблему молчаливого прекращения работы, описанную выше.

Кстати, на моей машине 1.1 пример из MSDN имеет ожидаемый результат; просто вторая строка не появляется, пока вы не подключите отладчик (или нет). В v2 мы перевернули вещи так, что событие UnhandledException срабатывает до того, как подключается отладчик, что, по-видимому, и ожидается большинством людей.

Джонатан Кельо CLR исключения PM Джонатан Кельо, 18 февраля 2005 г., 22:02

Тем не менее, мне все еще интересно, как поток пользовательского интерфейса выполняет прием, позволяющий вам иметь универсальный обработчик для всех исключений потока пользовательского интерфейса.

Более того, Мне очень интересно, как отключить диалог отладки .NET JIT только для моего приложения (без отключение его для всей машины, как показано здесь )

3 голосов
/ 19 августа 2009

Дело не в том, что любое исключение AppDomain завершает приложение, а в том, что необработанные исключения (любого рода) разрушают AppDomain и завершают приложение.

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

Необработанные исключения в потоке пользовательского интерфейса приведут к тому же самому.

2 голосов
/ 19 августа 2009

Помогает ли это вообще?

Улучшено поведение необработанных исключений в .NET 2.0

Кроме того, этот код, кажется, "тихо умирает". Вы ищете что-то еще?

using System;

namespace UnhandledException
{
    class Program
    {
        static void Main(string[] args)
        {
            AppDomain.CurrentDomain.UnhandledException += CurrentDomainUnhandledException;

            throw new NotImplementedException();
        }

        static void CurrentDomainUnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            Exception exception = (Exception)e.ExceptionObject;
            System.Console.WriteLine("exception=[" + exception.ToString() + "]");

            Environment.Exit(-1);
        }   
    }
}
...