我习惯于在处理异步操作的取消时执行异步模式:
public async Task InvokeAsync(CancellationToken cancellationToken)
{
using(cancellationToken.Register(handler.Stop))
{
try
{
await handler.HandleAsync();
}
catch(HandlerStoppedException ex)
{
cancellationToken.ThrowIfCancellationRequested();
throw;
}
}
}
该方法调用一个异步组件,该组件公开某种取消机制。当请求令牌信号取消时,取消令牌设置回调以调用取消机制。
我可以在测试中调用此方法在超时内运行其功能。
async Task TestInvoke()
{
using (var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(10))
{
try
{
await InvokeAsync(timeout.Token);
}
catch (TaskCancelledException ex)
{
if (ex.CancellationToken == timeout.Token)
{
throw new TimeoutException(
"Operation failed to complete in the allowed time.", ex);
}
throw;
}
}
}
我的期望是在OperationCanceledException
方法中抛出async
会导致方法返回的Task
转换为“已取消”状态。然后我预计任何等待此取消任务的尝试都应该抛出TaskCanceledException
。
在我当前的场景中(代码与上面的代码非常相似)我在等待任务时得到OperationCanceledException
。如果我检查任务的状态,我可以看到它处于“已取消”状态并且没有与之相关的异常。
更奇怪的是,如果我在该任务上调用Wait()
,则会抛出包含预期AggregateException
的{{1}}。
在什么情况下等待取消的任务会抛出TaskCanceledException
而不是更典型的OperationCanceledException
?
答案 0 :(得分:5)
在什么情况下等待取消的任务会抛出
OperationCanceledException
而不是更典型的TaskCanceledException
?
这个问题太宽泛了。即使列举了今天发生的所有场景,明天也可能会改变。
相反,我会说:TaskCanceledException
不是更典型的"。它最初用于基于动态任务的并行性,与异步编程无关。OperationCanceledException
是TaskCanceledException
的基类。在您的代码中,您永远不应该抓住TaskCanceledException
(除非您 执行基于动态任务的并行性并且需要访问TaskCanceledException.Task
)。改为抓住OperationCanceledException
。