У меня есть обработчик для Application.ThreadException
, но я обнаружил, что исключения не всегда передаются ему правильно.В частности, если я сгенерирую исключение с внутренним исключением из обратного вызова BeginInvoke
, мой обработчик ThreadException
не получит исключение external - он получит только inner исключение.
Пример кода:
public Form1()
{
InitializeComponent();
Application.ThreadException += (sender, e) =>
MessageBox.Show(e.Exception.ToString());
}
private void button1_Click(object sender, EventArgs e)
{
var inner = new Exception("Inner");
var outer = new Exception("Outer", inner);
//throw outer;
BeginInvoke(new Action(() => { throw outer; }));
}
Если я раскомментирую строку throw outer;
и нажму кнопку, то в окне сообщения отобразится внешнее исключение (вместе с его внутренним исключением):
System.Exception: Outer ---> System.Exception: Inner
--- Конец внутренней трассировки стека исключений ---
в WindowsFormsApplication1.Form1.button1_Click (Отправитель объекта,EventArgs e) в C: \ svn \ trunk \ Code Base \ Source.NET \ WindowsFormsApplication1 \ Form1.cs: строка 55
в System.Windows.Forms.Control.OnClick (EventArgs e)
в System.Windows.Forms.Button.OnClick (EventArgs e)
в System.Windows.Forms.Button.OnMouseUp (MouseEventArgs mevent)
в System.Windows.Forms.Control.WmMouseUp (сообщение & m, кнопка MouseButtons, щелчки Int32)
в System.Windows.Forms.Control.WndProc (Сообщение & m)
в System.Windows.Forms.ButtonBase.WndProc (сообщение & m)
в System.Windows.Forms.Button.WndProc (сообщение & m)
в System.Windows.Forms.Control.ControlNativeWindow.OnMessage (сообщение & m)
в System.Windows.Forms.Control.ControlNativeWindow.WndProc (Message & m)
в System.Windows.Forms.NativeWindow.Callback (IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
Но если throw outer;
находится внутри вызова BeginInvoke
, как в приведенном выше коде, то обработчик ThreadException
only получает внутреннее исключение.Внешнее исключение удаляется до вызова ThreadException
, и все, что я получаю, это:
System.Exception: Inner
(Нет стека вызововздесь, потому что inner
никогда не получалось. В более реалистичном примере, где я поймал одно исключение и обернул его для повторного выброса, был бы стек вызовов.)
То же самое происходит, еслиЯ использую SynchronizationContext.Current.Post
вместо BeginInvoke
: внешнее исключение удаляется, а обработчик ThreadException
получает только внутреннее исключение.
Я попытался обернуть больше слоев исключений вокруг, на случай, еслипросто удалял самое внешнее исключение, но это не помогло: очевидно, где-то есть цикл, выполняющий что-то вроде while (e.InnerException != null) e = e.InnerException;
.
Я использую BeginInvoke
, потому что у меня есть код, которыйнеобходимо сгенерировать необработанное исключение для немедленной обработки ThreadException
, но этот код находится внутри блока catch
выше стека вызовов (в частности, он находится внутри действия для Task
, и Task
будет перехватыватьисключение и остановить его распространение).Я пытаюсь использовать BeginInvoke
, чтобы отложить throw
до следующей обработки сообщений в цикле сообщений, когда я уже не внутри этого catch
.Я не привязан к конкретному решению BeginInvoke
;Я просто хочу выбросить необработанное исключение.
Как я могу вызвать исключение - включая его внутреннее исключение - для достижения ThreadException
, даже когда я нахожусь внутри чьего-либо другого catch
-все?
(я не могу вызвать мой метод-обработчик ThreadException
напрямую из-за зависимостей сборки: обработчик перехватывается кодом запуска EXE-файла, в то время как моя текущая проблема находится на нижнем уровнеDLL.)