2

BackgroundWorker.ErrorDoWork必须调用可能引发异常的委托时,如何获得有意义的信息?

我正在实现一个静态MsgBox类,它公开了向用户传达自定义消息的各种方式(使用自定义消息表单)。

公开的方法之一ShowProgress,实例化一个ProgressMessageBoxForm(派生自 custom MessageBoxForm),它在一些后台操作发生时显示一个进度条(让用户一直取消操作)。如果在模态表单上运行后台任务听起来很尴尬,请考虑这样的签名:

public static DialogResult ShowProgress(string title, string message, _
    Action<AsyncProgressArgs> progressAction)

这个想法是封装一个后台工作程序,将其“工作”委托给任何提供的方法(/处理程序),同时允许该方法“对话”并报告进度和取消......以及理想情况下的错误状态。在这种情况下,表单是否是模态的,在可取消的模态表单上的进度条中显示正在运行的任务的进度的能力,除非取消选中复选框以保持可见和显示,否则该表单也会自动关闭完成后的成功状态是必需的功能。

这是有AsyncProgressArgs问题的课程:

public class AsyncProgressArgs
{
    private readonly Action<int, string> _update;
    private readonly BackgroundWorker _worker;
    private readonly DoWorkEventArgs _workEventArgs;

    public AsyncProgressArgs(Action<int, string> updateProgress, BackgroundWorker worker, DoWorkEventArgs e)
    {
        _update = updateProgress;
        _worker = worker;
        _workEventArgs = e;
    }

    /// <summary>
    /// Reports progress to underlying <see cref="BackgroundWorker"/>.
    /// Increments <see cref="ProgressBar"/> value by specified <see cref="int"/> amount and
    /// updates the progress <see cref="Label"/> with specified <see cref="string"/> caption.
    /// </summary>
    public Action<int, string> UpdateProgress { get { return _update; } }

    /// <summary>
    /// Verifies whether asynchronous action is pending cancellation,
    /// in which case asynchronous operation gets cancelled.
    /// </summary>
    public void CheckCancelled()
    {
        _workEventArgs.Cancel = _worker.CancellationPending;
    }
}

的事件处理程序然后调用传递给自定义消息框的BackgroundWorker方法DoWork

protected virtual void worker_DoWork(object sender, DoWorkEventArgs e)
{
    // *** If RunWorkerCompletedEventArgs.Error caught exceptions,
    //     then this try/catch block wouldn't be needed:
    // try
    // {
           _startHandler(this, new AsyncProgressArgs(UpdateProgressAsync, _worker, e));
    // }
    // catch(Exception exception)
    // {
    //     if (MsgBox.Show(exception) == DialogResult.Retry)
    //     {
    //         BeginWork(_startHandler);
    //     }
    //     else
    //     {
    //         Hide();
    //     }
    // }
}

给定这样的方法:

private void AsyncProgressAction(AsyncProgressArgs e)
{
    // do some work:
    Thread.Sleep(200);

    // increment progress bar value and change status message:
    e.UpdateProgress(10, "Operation #1 completed.");

    // see if cancellation was requested:
    e.CheckCancelled();


    // do some work:
    Thread.Sleep(500);

    // increment progress bar value and change status message:
    e.UpdateProgress(30, "Operation #2 completed.");

    // see if cancellation was requested:
    e.CheckCancelled();

    // ...

    // throw new Exception("This should be caught by the BackgroundWorker");
}

调用代码可能如下所示:

MsgBox.ShowProgress("Async Test", "Please wait while operation completes.", _
    AsyncProgressAction);

一切都按预期工作(进度条移动,进程可以取消),直到在 action 方法中抛出异常。通常BackgroundWorker会捕获它并将其存储在它的Error属性中,但这里不会发生这种情况。

因此,传递的操作方法中的代码需要处理它自己的异常,如果不处理,它就会保持未处理状态,程序会以可怕的方式死去。

Error问题是,是否有可能拥有这样的构造,并且在过程完成时仍然能够以某种方式拥有有意义的属性?我希望能够Throw new Exception()在操作方法中的任何位置,并在封装的工作人员中处理它。

旁注,我之所以使用,是BackgroundWorker因为Task在完成所有工作之前我无法移动进度条,并且我想避免Thread直接处理对象实例。

编辑 这是一个非问题,编译的应用程序不会爆炸。实际上,我对调试器中断委托方法中抛出的异常感到困惑。正如下面评论中所指出的,执行/调试可以在之后继续,并且任何打算运行的错误处理逻辑都会运行。我期待BackgroundWorker以某种方式catch异常和调试器继续运行,但事实证明异常被捕获并且调试器仍然中断。

我之前应该读过这个:BackgroundWorker 中的未处理异常

4

1 回答 1

1

我之前应该读过这个:BackgroundWorker 中的未处理异常

这是一个非常非常长的问题,其中包含很多关于一个简单的非问题的上下文:VS 调试器停止并误导性地说“用户代码未处理异常”,就像未处理的异常一样......当它实际上意味着“BackgroundWorker任务引发了异常,调试器正在让你知道它,否则你会认为 BackgroundWorker 正在吞噬它。”

异常可以 F5'd / 忽略以恢复执行,异常确实RunWorkerCompletedEventArgs.Error按预期结束,并且部署的应用程序不会在用户面前爆炸。

发布此答案以从(溢出?)一堆未回答的问题中删除此问题...

于 2013-02-14T01:11:11.403 回答