【问题标题】:exception raised in BackgroundWorker.RunWorkerCompleted are not visible in Application.ThreadException handlerBackgroundWorker.RunWorkerCompleted 引发的异常在 Application.ThreadException 处理程序中不可见
【发布时间】:2012-09-18 13:44:39
【问题描述】:

我正在使用后台工作程序,发现在 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 处理程序异常中应该出现带有文本thread error 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 处理程序

error 'test exception 1' -- 这里只有原始异常

END ThreadException 处理程序

似乎 GetBaseException 仅针对 RunWorkerCompleted 事件执行。

【问题讨论】:

  • @PeterRitchie 实际上我认为 RunWorkerCompleted 在 GUI(主)线程中执行,因为从它访问 GUI 控件是安全的。可惜GetBaseException调用问题的链接坏了,我没找到这个buglink投票。还有一个线程 link 我通过 GetBaseException 找到了它

标签: c# exception-handling backgroundworker


【解决方案1】:

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

【讨论】:

  • 感谢您的评论,但我发现不是每次都会调用 GetBaseException,请参阅下面的帖子
猜你喜欢
  • 1970-01-01
  • 2014-06-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多