[英]General approach to handle Task cancellation correctly
I'm doing a code review, and I'm concerned about this pattern, seen all across that code: 我正在进行代码审查,并且我担心这种模式,贯穿所有代码:
try
{
await DoSomethingAsync();
await DoSomethingElseAsync();
// and so on...
}
catch (OperationCanceledException)
{
// all good, user cancelled
// log and return
return;
}
// handle other particular exceptions
// ...
catch (Exception ex)
{
// fatal error, alert the user
FatalErrorMessage(ex);
}
The part I'm concerned about is handling OperationCanceledException
. 我关心的部分是处理OperationCanceledException
。 Shouldn't this code be also handling AggregateException
and checking if the only inner exception is OperationCanceledException
? 这段代码不应该也处理AggregateException
并检查唯一的内部异常是否是OperationCanceledException
?
I know Task.Wait
or Task.Result
would throw an AggregateException
like that, rather than OperationCanceledException
. 我知道Task.Wait
或Task.Result
会抛出类似的AggregateException
,而不是OperationCanceledException
。 The author of the code assured me she only uses async/await
inside out and never uses Wait/Result
. 代码的作者向我保证她只使用async/await
out out并且从不使用Wait/Result
。 Thus, she doesn't like the idea of additionally observing AggregateException
for cancellation. 因此,她不喜欢另外观察AggregateException
进行取消的想法。 However, my point is some standard Task
-based BCL APIs could still be wrapping OperationCanceledException
with AggregateException
, eg because they still might be accessing Task.Result
internally. 但是,我的观点是一些标准的基于Task
的BCL API仍然可以使用AggregateException
包装OperationCanceledException
,例如因为它们仍然可能在内部访问Task.Result
。
Does it make sense? 是否有意义? Should we be worrying about handling both OperationCanceledException
and AggregateException
to observe cancellation correctly? 我们是否应该担心处理OperationCanceledException
和AggregateException
以正确观察取消?
However, my point is some standard Task-based BCL APIs could still be wrapping OperationCanceledException with AggregateException, eg because they still might be accessing Task.Result internally. 但是,我的观点是一些标准的基于任务的BCL API仍然可以使用AggregateException包装OperationCanceledException,例如因为它们仍然可能在内部访问Task.Result。
No, they won't do that. 不,他们不会这样做。
Should we be worrying about handling both OperationCanceledException and AggregateException to observe cancellation correctly? 我们应该担心同时处理OperationCanceledException和AggregateException以正确观察取消吗?
I would say no. 我会说不。 It is, of course, possible that an AggregateException
can contain an OperationCanceledException
, but it can also contain other particular exceptions
just as easily. 这是当然, 可能是一个AggregateException
可以包含OperationCanceledException
,但它也可以包含other particular exceptions
一样容易。
As long as you follow async best practices (ie, no async-over-sync or sync-over-async), then you don't have to worry about this. 只要您遵循异步最佳实践(即,没有异步同步或同步异步),您就不必担心这一点。
Well, it's definitely technically possible which is very easy to verify with this code: 嗯,这绝对是技术上可行的,这个代码很容易验证:
static void Main()
{
Test().Wait();
}
static async Task Test()
{
try
{
await ThrowAggregate();
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
static async Task ThrowAggregate()
{
ThrowException().Wait();
}
static async Task ThrowException()
{
throw new OperationCanceledException();
}
ThrowAggregate
stores the AggregateException inside the returned task so awaiting it still throws AggregateException
. ThrowAggregate
将AggregateException存储在返回的任务内,因此等待它仍会引发AggregateException
。 So if you want to be diligent you would need to catch AggregateException
too. 因此,如果您想勤奋工作,那么也需要捕获AggregateException
。
However, it's very unlikely that any method in the BCL would do that and if it did you have bigger issues than exception handling since your doing async over sync. 但是,BCL中的任何方法都不太可能这样做,如果它确实存在比异常处理更大的问题,因为您执行异步过度同步。 I would be more worried about your own code. 我会更担心你自己的代码。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.