tl; dr: это отладчик . Отделись, и ты не получишь это странное поведение.
Хорошо. Я немного поэкспериментировал с новым проектом бренда Spankin 'и получил результат. Я начну с публикации кода, чтобы вы тоже могли присоединиться к веселью и увидеть его воочию.
Кодекс
Пожалуйста, напишите мне на почту (не связано)
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 (и сам Forms) не будет выгружен между сеансами отладки, в результате чего строка Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException, false);
выдает InvalidOperationException
, если вы измените UnhandledExceptionMode
аргумент между пробегами. РЕДАКТИРОВАТЬ: или вообще, если установлено CatchException
Это не является строго необходимым для этого расследования, но если вы собираетесь поиграть и изменить UnhandledExceptionMode
- что, я думаю, вы, вероятно, сделаете, если будете запускать этот код самостоятельно - эта настройка спасет вас от душевной боли.
Тестирование
Внутри отладчика
Добавить в пользовательский интерфейс
- Нажмите Добавьте пользовательский интерфейс
- Получить помощник «необработанное исключение» в отладчике
F5
для продолжения исполнения
- Появится диалоговое окно, указывающее, что обработчик приложения получил событие исключения из потока пользовательского интерфейса
- Нажмите OK
- Приложение не аварийно завершает работу, поэтому смойте и повторите.
Киньте в фоновый поток
- Клик Бросок в фоновом режиме
- Появится диалоговое окно, указывающее, что обработчик AppDomain получил событие исключения из фонового потока
- Получить помощник «необработанное исключение» в отладчике
F5
для продолжения исполнения
goto 2
. На самом деле.
Здесь кажется, что обработчик AppDomain превосходит отладчик по любой причине. Однако после того, как AppDomain завершил работу с ним, отладчику удается обнаружить необработанное исключение. Но то, что происходит дальше, вызывает недоумение: обработчик AppDomain снова запускается. И опять. И снова, до бесконечности . Помещение точки останова в обработчик означает, что это не является рекурсивным (по крайней мере, не в .NET), поэтому , вероятно, не закончится переполнением стека.
Теперь давайте попробуем ...
Вне отладчика
Пользовательский интерфейс
Та же процедура, тот же результат - за исключением того, что помощник отладчика явно отсутствовал. Программа по-прежнему не аварийно завершала работу, потому что UnhandledExceptionMode.CatchException
делает то, о чем говорит, и обрабатывает исключение «внутренне» (по крайней мере, в Forms) вместо передачи его в Feds AppDomain.
Фоновая нить
Теперь это интересно.
- Нажмите Бросьте в фоновом режиме
- Появится диалоговое окно, указывающее, что обработчик AppDomain получил событие исключения из фонового потока
- Получить диалог сбоя Windows
- Нажмите
Debug
, чтобы получить исключение при отладке JIT
- Получить помощник "необработанное исключение"
F5
продолжить
- Выход из программы
Во-первых, домен приложений не зацикливается, как это происходит с подключенным отладчиком, а во-вторых, своевременное подключение отладчика из диалогового окна ошибки Windows не вызывает такое странное поведение.
Заключение
Кажется, что отладчик делает что-то странное в отношении необработанных исключений, попадающих в AppDomain. Я не знаю много о том, как отладчик делает свое волшебство, поэтому я не буду спекулировать, но цикл only происходит, когда отладчик подключен, поэтому, если цикл является проблемой, отсоединение является одним из обходных путей Вы могли бы использовать (возможно, используя Debugger.Launch()
, чтобы дать себе время для повторного присоединения позже, если вам это нужно).
<3 </p>