使用ContinueWith时如何捕获OperationCanceledException [英] How to catch an OperationCanceledException when using ContinueWith

查看:191
本文介绍了使用ContinueWith时如何捕获OperationCanceledException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些代码将从.NET 4.5的可爱的asyncawait关键字降级为.NET 4.0.我正在使用ContinueWith创建类似于await工作方式的延续.

I have some code I'm downgrading from .NET 4.5's lovely async and await keywords to .NET 4.0. I'm using ContinueWith to create a continuation similar to the way await works.

基本上,我的旧代码是:

Basically, my old code was:

var tokenSource = newCancellationTokenSource();
var myTask = Task.Run(() =>
{
    return MyStaticClass.DoStuff(tokenSource.Token);
}, tokenSource.Token);
try
{
    var result = await myTask;
    DoStuffWith(result);
}
catch (OperationCanceledException)
{
    // Cancel gracefully.
}

(如人们所料,MyStaticClass.DoStuff(token)会定期调用token.ThrowIfCancellationRequested().)

(As one might expect, MyStaticClass.DoStuff(token) regularly calls token.ThrowIfCancellationRequested().)

我的新代码如下:

var tokenSource = new CancellationTokenSource();
try
{
    Task.Factory.StartNew(() =>
    {
        return MyStaticClass.DoStuff(tokenSource.Token);
    }, tokenSource.Token)
    .ContinueWith(task =>
    {
        var param = new object[1];
        param[0] = task.Result;
        // I need to use Invoke here because "DoStuffWith()" does UI stuff.
        Invoke(new MyDelegate(DoStuffWith, param));
    });
}
catch (OperationCanceledException)
{
    // Cancel gracefully.
}

但是,OperationCanceledException从未被捕获.这是怎么回事?我在哪里放置try/catch块?

However, the OperationCanceledException is never caught. What's going on? Where do I put my try/catch block?

推荐答案

取消处理的方式与其他异常不同.基本上,您可以使用以下模式:

Cancellation is handled differently from other exceptions. Basically, you can use this pattern:

Task.Factory.StartNew(() =>
{
    // The task
}, tokenSource.Token)
.ContinueWith(task =>
{
    // The normal stuff
}, TaskContinuationOptions.OnlyOnRanToCompletion)
.ContinueWith(task =>
{
    // Handle cancellation
}, TaskContinuationOptions.OnlyOnCanceled)
.ContinueWith(task =>
{
    // Handle other exceptions
}, TaskContinuationOptions.OnlyOnFaulted);

或另一种选择:

Task.Factory.StartNew(() =>
{
    // The task
}, tokenSource.Token)
.ContinueWith(task =>
{
    switch (task.Status)
    {
    case TaskStatus.RanToCompletion:
        // The normal stuff
        break;
    case TaskStatus.Canceled:
        // Handle cancellation
        break;
    case TaskStatus.Faulted:
        // Handle other exceptions
        break;
    }
});

在您的情况下,您没有捕获任何东西,因为:

In your case, you're not catching anything because:

  • Task.Factory.StartNew立即返回并且始终成功.
  • 您的延续总是运行的
  • 访问 task.Result 会自任务以来抛出AggregateException被取消
  • 由于异常是从线程池线程中抛出的,因此任何东西都不对其进行处理.哎呀.接下来会发生什么

  • Task.Factory.StartNew returns immediately and always succeeds.
  • Your continuation always runs
  • Accessing task.Result throws an AggregateException since the task is canceled
  • The exception is not handled by anything since it's thrown from a thread pool thread. Oops. What happens next depends on the framework version:

  • 在.NET中< 4.5,由于您有一个未观察到的异常,一旦失败的任务完成,该过程将立即终止.
  • 在.NET> = 4.5中,该异常将被静默删除.

这篇关于使用ContinueWith时如何捕获OperationCanceledException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆