C# 使用ContinueWith时如何捕获OperationCanceledException

C# 使用ContinueWith时如何捕获OperationCanceledException,c#,asynchronous,.net-4.0,async-await,C#,Asynchronous,.net 4.0,Async Await,我有一些代码正在从.NET4.5可爱的async和wait关键字降级到.NET4.0。我正在使用ContinueWith创建一个类似于wait工作方式的延续 基本上,我的旧代码是: var tokenSource = newCancellationTokenSource(); var myTask = Task.Run(() => { return MyStaticClass.DoStuff(tokenSource.Token); }, tokenSource.Token); tr

我有一些代码正在从.NET4.5可爱的
async
wait
关键字降级到.NET4.0。我正在使用
ContinueWith
创建一个类似于
wait
工作方式的延续

基本上,我的旧代码是:

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()

我的新代码如下所示:

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.
}

但是,
操作取消异常
从未被捕获。发生什么事?我应该将try/catch块放在哪里?

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

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;
    }
});
在您的情况下,您没有捕获任何内容,因为:

  • Task.Factory.StartNew
    立即返回并始终成功
  • 你的续集总是在运行
  • 由于任务被取消,访问会引发一个
    聚合异常
  • 由于异常是从线程池线程中抛出的,因此任何东西都不会处理它。哎呀。接下来会发生什么:

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

请注意,您可以将wait与.NET 4.0一起使用,使用这些概念可以了解可能出现的问题,但不幸的是,我的执行情况不佳,或者它对我不起作用。