【问题标题】:How to catch an OperationCanceledException when using ContinueWith使用 ContinueWith 时如何捕获 OperationCanceledException
【发布时间】:2015-05-15 06:50:24
【问题描述】:

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

基本上,我的旧代码是:

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

但是,OperationCanceledException 永远不会被捕获。这是怎么回事?我应该把 try/catch 块放在哪里?

【问题讨论】:

标签: c# asynchronous .net-4.0 async-await


【解决方案1】:

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

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 立即返回并始终成功。
  • 您的延续始终运行
  • 访问task.Result 会抛出AggregateException,因为任务已取消
  • 异常没有被任何东西处理,因为它是从线程池线程中抛出的。哎呀。接下来会发生什么depends on the framework version:

    • 在 .NET
    • 在 .NET >= 4.5 中,异常将被静默丢弃。

【讨论】:

  • 这些概念揭示了可能出现的问题,但不幸的是,要么我执行不力,要么它对我不起作用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-11-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-19
相关资源
最近更新 更多