У меня есть обработчик Application.ThreadException
, но я обнаружил, что исключения не всегда правильно передаются ему. В частности, если я выкидываю исключение-with-inner-exception из обратного вызова BeginInvoke
, мой обработчик ThreadException
не получает внешнее исключение - он получает только внутреннее исключение.
Пример кода:
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: Внутренний
--- Конец внутренней проверки стека исключений ---
в 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(Message & m, кнопка MouseButtons, клики Int32)
в System.Windows.Forms.Control.WndProc(Message & m)
в System.Windows.Forms.ButtonBase.WndProc(Message & m)
в System.Windows.Forms.Button.WndProc(Message & m)
в System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message & 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
получает только внутреннее исключение. Внешнее исключение удаляется до вызова ThreadException
, и все, что я получаю, это:
System.Exception: Внутренний
(Здесь нет стека вызовов, потому что inner
никогда не попадался. В более реалистичном примере, когда я поймал одно исключение и завернул его в повторный бросок, будет стек вызовов.)
То же самое происходит, если я использую SynchronizationContext.Current.Post
вместо BeginInvoke
: внешнее исключение удаляется, а обработчик ThreadException
получает только внутреннее исключение.
Я попробовал обернуть больше слоев исключений извне, в случае, если он просто отменил самое внешнее исключение, но это не помогло: по-видимому, где-то там цикл делал что-то вдоль строк while (e.InnerException != null) e = e.InnerException;
.
Я использую BeginInvoke
, потому что у меня есть код, который должен вызывать необработанное исключение, которое немедленно обрабатывается ThreadException
, но этот код находится внутри блока catch
выше стека вызовов (в частности, он внутри действия для a Task
, а Task
поймает исключение и прекратит его распространение). Я пытаюсь использовать BeginInvoke
для задержки throw
, пока в следующий раз сообщения не будут обработаны в цикле сообщений, когда я больше не буду внутри catch
. Я не привязан к конкретному решению BeginInvoke
; Я просто хочу бросить необработанное исключение.
Как я могу заставить исключение, включая его внутреннее исключение, достичь ThreadException
, даже если я внутри кого-то еще catch
-all?
(Я не могу вызвать метод ThreadException
-handler напрямую из-за зависимостей сборки: обработчик подключен кодом запуска EXE, тогда как моя текущая проблема находится в DLL более низкого уровня.)