BackgroundWorker.RunWorkerCompleted中引发的异常在Application.ThreadException处理程序中不可见

时间:2012-09-18 13:44:39

标签: c# exception-handling backgroundworker

我正在使用后台工作程序,发现RunWorkerCompleted事件处理程序中引发的新异常在Application.ThreadException处理程序中不可见。例如: Program.cs中的某个地方:

    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

        Application.ThreadException += delegate(object o, ThreadExceptionEventArgs args)
        {
            if (args.Exception != null)
                Console.WriteLine("thread error {0}", args.Exception.Message);
        };

        Application.Run(new Form1());
    }

然后在按钮单击(仅用于测试目的)

        var bw = new BackgroundWorker();
        bw.DoWork += delegate(object o, DoWorkEventArgs args) { /* some calculations here */ };
        bw.RunWorkerCompleted += delegate(object sender1, RunWorkerCompletedEventArgs eventArgs)
        { 
            try
            {
                //in run worker completed exception occurs
                throw new ApplicationException("test exception 1");
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                Console.WriteLine("throwing new exception");
                throw new ApplicationException(string.Format("catched '{0}'", ex.Message), ex);
            }
        };

        bw.RunWorkerAsync();

程序输出如下:

测试例外1

抛出新异常

线程错误测试异常1

我相信在Application.ThreadException处理程序异常中会出现文本线程错误catched'test exception 1',而不是原始异常。

你能帮助我 - 它为什么会发生以及它如何解决?这只是示例代码。 实际代码中的RunWorkerCompleted处理程序中有几个嵌套方法。其中一些方法会捕获异常,并在内部异常中添加其他信息和原始异常。所以在Application.ThreadException处理程序中,我不仅要获得抛出的原始异常,还要获得整个链。

谢谢


我发现没有通过按钮点击(例如)

来调用未处理的异常的GetBaseException

假设在Program.Main方法中有TreadException事件处理程序,如下所示:

        Application.ThreadException += (o, args) =>
        {
            Console.WriteLine("BEGIN ThreadException handler");
            ShowException(args.Exception);
            Console.WriteLine("END ThreadException handler\r\n");
        };

和Program.ShowException方法如下:

    static void ShowException(Exception ex)
    {
        var tab = "";
        while (ex != null)
        {
            Console.WriteLine("{1}error '{0}'", ex.Message, tab);
            tab += '\t';
            ex = ex.InnerException;
        }
    }

代码

        try
        {
            throw new ApplicationException("button click 1");
        }
        catch (Exception ex)
        {
            throw new ApplicationException(string.Format("BC caught '{0}'", ex.Message), ex);
        }
单击按钮执行

,它会产生以下输出:

BEGIN ThreadException处理程序

错误'BC抓住'按钮点击1''

  • 错误'按钮单击1'*

END ThreadException处理程序

如您所见 - 整个例外链都可用。

但ThreadException处理程序仅显示RunWorkerCompleted事件处理程序中非常相似代码的原始异常(下面的代码是在按钮单击事件中执行的):

        var bw = new BackgroundWorker();
        bw.DoWork += delegate(object o, DoWorkEventArgs args) 
        { 
            /* some calculations here */
        };
        bw.RunWorkerCompleted += delegate(object sender1, RunWorkerCompletedEventArgs eventArgs)
        { 
            try
            {
                //in run worker completed exception occurs
                Console.WriteLine("RWC exception test, throwing");
                throw new ApplicationException("test exception 1");
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                Console.WriteLine("RWC got exception, throwing new");
                throw new ApplicationException(string.Format("RWC caught '{0}'", ex.Message), ex);
            }
        };

        bw.RunWorkerAsync();

,输出如下:

RWC异常测试,抛出

测试例外1

RWC异常,抛出新的

BEGIN ThreadException处理程序

错误'测试异常1' - 此处只有原始异常

END ThreadException处理程序

似乎只对RunWorkerCompleted事件执行GetBaseException。

1 个答案:

答案 0 :(得分:1)

无论出于何种原因,框架都会针对您抛出的异常调用Exception.GetBaseException并使用 异常传递到ThreadException事件。如果您不想这样做,请不要传入基本/内部异常。