Почему исключения AppDomain неизменно завершают работу приложения?

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

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

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

Самое главное, что я хотел бы иметь в этом случае, это "тихо" завершить процесс - без отображения диалогового окна 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();            
}

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

3 ответа

Решение

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

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

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

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

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

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

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

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

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

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

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

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

Это помогает вообще?

Улучшено поведение необработанных исключений в.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);
        }   
    }
}
Другие вопросы по тегам