将 OperationCanceledException 关联到 CancellationToken 的正确方法

Enr*_*one 5 c# cancellation async-await cancellation-token .net-core

我正在使用一个支持取消的异步 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;
}
Run Code Online (Sandbox Code Playgroud)

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

  • 检查对象的IsCancellationRequested属性tokenwhen (token.IsCancellationRequested)
  • 检查对象的CancellationToken属性exwhen (ex.CancellationToken == token)

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

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

Ste*_*ary 5

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

你不能做到这一点正好,但你可以“赶上只有我提供的令牌已取消了取消例外”,这通常是足够好的。

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

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

  • 感谢你的回答。如果我调用的 api 正在观察链接的取消令牌,那么“ex.CancellationToken”实际上是**链接的**,而不是我从外部提供的,对吧? (2认同)