14

Application.ThreadException在抛出异常并在事件处理程序中捕获它们时,我看到了一些奇怪的行为。

基本上下面示例中发生的事情是DoWorkBackgroundWorker. 事件RunWorkerCompleted处理程序以原始异常作为内部异常重新引发新异常。

为什么内部异常出现在ThreadException事件处理程序中而不是实际异常被抛出?如果我没有在RunWorkerCompleted事件处理程序中提供内部异常,则会显示正确的异常。

using System;
using System.Windows.Forms;
using System.ComponentModel;

namespace WierdExceptionApp
{
    class WierdExceptionForm : Form
    {
        BackgroundWorker worker = new BackgroundWorker();

        public WierdExceptionForm()
        {
            worker.DoWork += new DoWorkEventHandler(worker_DoWork);
            worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
            worker.RunWorkerAsync();
        }

        void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                throw new Exception("worker_RunWorkerCompleted", e.Error);
            }
        }

        void worker_DoWork(object sender, DoWorkEventArgs e)
        {
            throw new Exception("worker_DoWork");
        }

        [STAThread]
        static void Main()
        {
            Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
            Application.Run(new WierdExceptionForm());
        }

        static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
        {
            MessageBox.Show(e.Exception.Message);
        }
   }
}
4

2 回答 2

12

RunWorkerCompleted 事件由使 Control.Invoke() 工作的 WF 管道从 BGW 线程封送到 UI 线程。本质上,有一个由消息循环清空的委托队列。执行此操作的代码 Control.InvokeMarshaledCallbacks(),您将在调用堆栈上看到它,它有一个 catch (Exception) 子句来捕获未处理的异常。该子句调用 Application.OnThreadException,传递 Exception.GetBaseException() 的值。

嗯,这就解释了为什么你只看到内部异常。为什么这样做有点不清楚。可能会切掉 UI 线程中代码的堆栈帧,因为真正的异常来自后台线程,否则会非常混乱。

于 2008-12-07T21:33:50.607 回答
1
        if (e.Error != null)
        {
            throw new Exception("worker_RunWorkerCompleted", new Exception("Inner", new Exception("Inner inner")));
        }

最后你会得到“内在的内在”。看来这是 Application_ThreadException 方法查看最内部异常的行为。

于 2008-12-07T19:08:31.680 回答