使用异常作为中断/导航.这是个坏主意吗

本文关键字:导航 异常 中断 | 更新日期: 2023-09-27 18:31:40

我正在开发一个基本的Windows窗体应用程序,该应用程序具有一些执行"繁重"工作的功能。因此,我在后台工作线程的帮助下一起使用 ThreadAbortExceptions - 如下所示:

public class AbortableBackgroundWorker : BackgroundWorker

-取消执行功能。我们称这些函数为"HeavyFunction()"

但是,现在 ThreadAbortException 已被捕获在 HeavyFunction() 中,我需要以某种方式回到称为 HeavyFunction() 的"MainForm.cs"类。这是为了确保我正确关闭其他打开的连接(例如编写器)并向用户显示消息。所以,我只是从 HeavyFunction() 中抛出一个异常,然后在 MainForm 中捕获它,就像这样(这是在 HeavyFunction() 中):

catch (ThreadAbortException tae)
            {
                //Deligate abortion upwards.
                SomeWriter.DeleteAndClose();
                throw new ArgumentException("relevant message or identifier for later use here");
                //close and delete
            }

抛出的异常随后在 MainForm 中的"DoWork"函数中捕获,并相应地进行处理。

我的问题 - 这是一种不好的做法吗?

我对Threads和Thread.Abort不太满意(因此首先是后台工作者)

子问题 - 有哪些简单优雅的解决方案可以将响应从调用类中冒泡回表单?

使用异常作为中断/导航.这是个坏主意吗

这是一种不好的做法吗?

是的,ThreadAbortException通常是一种不好的做法。

IMO,如果 MS 从未发明过这个例外,那就更好了,因为许多人认为TAE是停止任何操作的合法方式。

所以,我只是从 HeavyFunction()
中抛出一个异常 有哪些简单优雅的解决方案可以回泡响应

你刚刚重新发明了TPL的OperationCancelledException
简单而优雅的解决方案是使用 TPL 及其优雅的取消模式:

          var cts = new CancellationTokenSource();
          Task
            .Factory
            .StartNew(() => 
             { 
                 /* HeavyFunction */ 
                 while (someCondition)
                 {
                    cts.Token.ThrowIfCancellationRequested();
                    /*  do something */
                 }
             }, cts.Token);
如果只想在

取消HeavyFunction时执行某些操作,请在StartNew后添加延续:

.StartNew(/*  */)
.ContinueWith(() => {/* some action */}, TaskContinuationOptions.OnlyOnCanceled);

BackgroundWorker 支持取消方案。

UI 线程必须调用 bw。CancelAsync() 在 DoWork 中,您需要检查 bw。取消待处理属性,如果这是真的,你应该退出DoWork。

private void buttonCancel_Click(object sender, RoutedEventArgs e)
{
if (bw.WorkerSupportsCancellation == true)
{
    bw.CancelAsync();
}
}
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
for (int i = 1; (i <= 10); i++)
{
    if ((worker.CancellationPending == true))
    {
        e.Cancel = true;
        break;
    }
    else
    {
        // Do something heavy
    }
}
}