Почему внутреннее исключение достигает обработчика ThreadException, а не фактического выданного исключения? - PullRequest
13 голосов
/ 07 декабря 2008

Я вижу странное поведение при создании исключений и перехвате их в обработчике событий Application.ThreadException.

По сути, в приведенном ниже примере происходит исключение в обработчике DoWork события BackgroundWorker. Обработчик события 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);
        }
   }
}

Ответы [ 2 ]

10 голосов
/ 08 декабря 2008

Событие RunWorkerCompleted передается из потока BGW в поток пользовательского интерфейса с помощью WF-соединения, которое заставляет Control.Invoke () работать. По сути, есть очередь с делегатами, которая очищается циклом сообщений. Код, который делает это, Control.InvokeMarshaledCallbacks (), вы увидите это в стеке вызовов, имеет предложение catch (Exception) для перехвата необработанных исключений. Это предложение вызывает Application.OnThreadException, передавая значение Exception.GetBaseException ().

Ну, это объясняет, почему вы видите только внутреннее исключение. Почему так сделано, немного неясно. Возможно отрезать стековые кадры кода в потоке пользовательского интерфейса, которые в противном случае довольно запутаны, поскольку настоящее исключение произошло из фонового потока.

0 голосов
/ 07 декабря 2008
        if (e.Error != null)
        {
            throw new Exception("worker_RunWorkerCompleted", new Exception("Inner", new Exception("Inner inner")));
        }

В конце вы получаете «внутреннее внутреннее». Похоже, что это поведение метода Application_ThreadException, чтобы посмотреть на самое внутреннее исключение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...