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

时间:2013-09-17 10:37:14

标签: c# .net exception exception-handling

我正在开发一个基本的Windows窗体应用程序,它有一些功能正在做“重”工作。因此,我在后台工作者的帮助下一起使用ThreadAbortExceptions,如下所示:

public class AbortableBackgroundWorker : BackgroundWorker

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

但是,既然已经在HeavyFunction()中捕获了ThreadAbortException,我还是需要回到调用HeavyFunction()的“MainForm.cs”类。这是为了确保我正确关闭其他打开的连接(例如Writer)并向用户显示消息。所以,我只是从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(因此首先是背景工作者)

子问题 - 有哪些简单优雅的解决方案可以将响应从一个被调用的类中反映回来?

2 个答案:

答案 0 :(得分:1)

  

这是一种不好的做法吗?

是的,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);

答案 1 :(得分:0)

BackgroundWorker支持取消方案。

UI线程必须在DoWork内调用bw.CancelAsync(),你需要检查bw.CancellationPending属性,如果是,你应该退出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
    }
}
}