问题描述
我正在使用一个支持取消的异步 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;
}
对于上面代码的异常过滤器我基本上有两个想法:
- 检查
IsCancellationRequested
对象的token
属性:when (token.IsCancellationRequested)
- 检查
CancellationToken
对象的ex
属性:when (ex.CancellationToken == token)
进行我想要执行的检查的正确方法是什么?上面显示的两种方式是否等效?有最佳实践吗?
重要说明:我知道上面显示的代码可以用更有效的方式编写,因为捕获异常是一项代价高昂的操作。最好的办法可能是完全删除第一个 catch
块,并且仅当且仅当它与 Exception
对象的取消无关时才捕获 token
。我知道这一点,但这不是我的问题的重点。 我在问题中这样编写代码只是为了清楚起见,因为我的问题的重点是如何将 OperationCanceledException
与导致异常本身。
解决方法
我希望能够捕获 OperationCanceledException 当且仅当它是由于取消提供的取消令牌而引发的异常时。
您不能完全地做到这一点,但是您可以“仅在我提供的令牌已被取消时才捕获取消的异常”,这通常已经足够了。
when (token.IsCancellationRequested)
就是您想要的。
不要检查 ex.CancellationToken
,因为您调用的方法可能正在观察链接的取消令牌,这与您提供的不同。