Ответ 1
tl; dr: Это отладчик. Отсоедините, и вы не получите это странное поведение.
Хорошо. Я немного экспериментировал с новым проектом Brand Spankin'a и придумал результат. Я начну с публикации кода, чтобы вы тоже могли присоединиться к веселью и увидеть его на собственном опыте.
Teh Codez
plz напишите им мне (не связанный)
Form1.cs
Вам понадобятся две кнопки в форме. Подпишите их соответствующим образом, чтобы он ослепительно очевиден, что вы делаете.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
throw new InvalidOperationException("Exception thrown from UI thread");
}
private void button2_Click(object sender, EventArgs e)
{
new Thread(new ThreadStart(ThrowThreadStart)).Start();
}
private static void ThrowThreadStart()
{
throw new InvalidOperationException("Exception thrown from background thread");
}
}
Program.cs
static class Program
{
[STAThread]
static void Main()
{
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
Application.ThreadException += Application_ThreadException;
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException, false);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
{
if (e.Exception != null)
{
MessageBox.Show(string.Format("+++ Application.ThreadException: {0}", e.Exception.Message));
}
else
{
MessageBox.Show("Thread exception event fired, but object was not an exception");
}
}
static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Exception ex = e.ExceptionObject as Exception;
if (ex != null)
{
MessageBox.Show(string.Format("*** AppDomain.UnhandledException: {0}", ex.Message));
}
else
{
MessageBox.Show("Unhandled exception event fired, but object was not an exception");
}
}
}
Файл проекта
Отключите хостинг-процесс, иначе AppDomain (и сами формы) не будет выгружен между сеансами отладки, что сделает строку Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException, false);
throw InvalidOperationException
, если вы измените аргумент UnhandledExceptionMode
между прогонами. EDIT: или вообще, если установлено CatchException
Это не является строго необходимым для этого исследования, но если вы собираетесь играть и изменить этот параметр избавит вас от боли.
UnhandledExceptionMode
- что я ожидаю, вы, вероятно, будете, если вы сами запускаете этот код -
Тестирование
Внутри отладчика
Вбросить в поток пользовательского интерфейса
- Нажмите "Бросить в пользовательский интерфейс"
- Получите хелпер "необработанного исключения" в отладчике
-
F5
для продолжения выполнения - Диалог покажет, что обработчик приложения получил событие исключения из потока пользовательского интерфейса.
- Нажмите "ОК"
- Приложение не сбой, поэтому не стесняйтесь ополаскивать и повторять.
Выбросить фоновый поток
- Нажмите "Бросок в фоновом режиме"
- Диалог покажет, что обработчик AppDomain получил событие исключения из фонового потока
- Получите хелпер "необработанного исключения" в отладчике
-
F5
для продолжения выполнения -
goto 2
. На самом деле.
Кажется, что обработчик AppDomain превосходит отладчик по любой причине. Однако после того, как приложение AppDomain с этим связано, отладчик действительно может получить необработанное исключение. Но то, что происходит дальше, вызывает недоумение: обработчик AppDomain снова запускается. И опять. И снова, до бесконечности. Помещение контрольной точки в обработчик указывает, что это не рекурсивно (по крайней мере, не в .NET), поэтому это, вероятно, не закончится переполнением стека.
Теперь попробуем...
За пределами отладчика
поток пользовательского интерфейса
Такая же процедура, тот же результат - за исключением того, что помощник отладчика заметно отсутствовал. Программа все еще не сработала, потому что UnhandledExceptionMode.CatchException
делает то, что она говорит, что она будет делать, и обрабатывает исключение "внутренне" (по крайней мере, в Формах), а не увеличивая его до Feds AppDomain.
Фоновая нить
Теперь это интересно.
- Нажмите "Бросок в фоновом режиме"
- Диалог покажет, что обработчик AppDomain получил событие исключения из фонового потока
- Получить диалоговое окно сбоя Windows
- Нажмите
Debug
, чтобы вырвать исключение с помощью отладки JIT - Получить хелпер с необработанным исключением
-
F5
продолжить - Программа выходит
Во-первых, AppDomain не входит в циклы, как при подключенном отладчике, и, во-вторых, приведение отладчика точно в срок из диалогового окна ошибки Windows не вызывает это странное поведение.
Заключение
Кажется, что отладчик делает что-то странное относительно необработанных исключений, пробираясь к AppDomain. Я мало знаю о том, как отладчик делает свою магию, поэтому я не буду спекулировать, но цикл только возникает, когда отладчик подключен, поэтому, если цикл является проблемой, отсоединение является одним обходной путь, который вы могли бы использовать (возможно, используя Debugger.Launch()
, чтобы дать себе время для повторного подключения позже, если вы этого потребуете).
< 3