【问题标题】:Proper way to correlate an OperationCanceledException to a CancellationToken将 OperationCanceledException 与 CancellationToken 相关联的正确方法
【发布时间】:2021-04-21 21:36:27
【问题描述】:

我正在使用一个支持取消的异步 api,并且我正在向该 api 传递一个 CancellationToken 实例。像往常一样,如果在传递的令牌上请求取消,我正在调用的 api 将抛出 OperationCanceledException(这是 .NET 框架的标准协作取消模式)。

我希望能够捕获OperationCanceledException当且仅当它是由于取消提供的取消令牌而引发的异常。

以下代码说明了我想要实现的目标:

try 
{
    await _service.DoSomethingAsync(cancellationToken: token);
}
catch (OperationCanceledException ex) when ( /* here I want a condition signifying that the OperationCanceledException is caused by the cancellation of the token object */)
{
    // avoid logging the exception: this is raised by design (cooperative cancellation)
    throw;
}
catch (Exception ex) 
{
    _logger.LogError(ex, "An error occurred: {0}", ex.Message);
    throw;
}

对于上面代码的异常过滤,我基本上有两个想法:

  • 检查token 对象上的IsCancellationRequested 属性:when (token.IsCancellationRequested)
  • 检查ex 对象上的CancellationToken 属性:when (ex.CancellationToken == token)

进行我要执行的检查的正确方法是什么?上面显示的两种方式是否等效?有最佳做法吗?

重要提示:我知道上面显示的代码可以用更有效的方式编写,因为捕获异常是一项昂贵的操作。最好的办法可能是完全删除第一个catch 块,并且仅当且仅当它与取消token 对象无关时才捕获Exception。我知道这一点,但这不是我问题的重点。 为了清楚起见,我以这种方式编写了问题中的代码,因为我的问题的重点是如何正确地将 OperationCanceledException 与导致异常本身的 CancellationToken 相关联。

【问题讨论】:

  • 前者更有意义,因为两个令牌都可能被取消

标签: c# .net-core async-await cancellation cancellation-token


【解决方案1】:

当且仅当它是由于取消提供的取消令牌而引发的异常时,我希望能够捕获 OperationCanceledException。

您不能完全这样做,但是您可以“仅当我提供的令牌已被取消时才捕获已取消的异常”,这通常已经足够了。

when (token.IsCancellationRequested) 是你想要的。

不要检查ex.CancellationToken,因为您调用的方法可能正在观察链接的取消令牌,这与您提供的不同。

【讨论】:

  • 感谢您的回答。如果我正在调用的 api 正在观察链接的取消令牌,那么 ex.CancellationToken 实际上是 链接的一个,而不是我从外部提供的那个,对吧?
猜你喜欢
  • 2013-02-21
  • 2011-10-05
  • 1970-01-01
  • 2018-08-05
  • 1970-01-01
  • 2018-06-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多