我正在进行代码审核,我对这种模式很关注,在整个代码中都看到了:
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);
}
我关注的部分是处理OperationCanceledException
。此代码不应该同时处理AggregateException
并检查唯一内部例外是否为OperationCanceledException
吗?
我知道Task.Wait
或Task.Result
会抛出AggregateException
,而不是OperationCanceledException
。该代码的作者向我保证,她只在内部使用async/await
,从不使用Wait/Result
。因此,她不喜欢另外观察AggregateException
取消的想法。但是,我的观点是一些标准的基于Task
的BCL API仍然可以OperationCanceledException
包裹AggregateException
,例如因为他们可能仍在内部访问Task.Result
。
有意义吗?我们是否应该担心处理OperationCanceledException
和AggregateException
以正确观察取消?
答案 0 :(得分:4)
但是,我的观点是一些标准的基于任务的BCL API仍可能使用AggregateException包装OperationCanceledException,例如因为他们仍然可能在内部访问Task.Result。
不,他们不会这样做。
我们是否应该担心处理OperationCanceledException和AggregateException以正确观察取消?
我会说不。当然,可能 AggregateException
可以包含OperationCanceledException
,但它也可以轻松地包含other particular exceptions
。
只要您遵循异步最佳做法(即没有异步同步或同步异步),您就不必担心这一点。
答案 1 :(得分:3)
嗯,这绝对是技术上可行的,使用此代码很容易验证:
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
将AggregateException存储在返回的任务中,等待它仍然会抛出AggregateException
。所以,如果你想要勤奋,你也需要抓住AggregateException
。
但是,非常不可能 BCL中的任何方法都可以做到这一点,如果它确实存在问题,那么因为异步过度同步,你会遇到更大的问题。 我会更担心你自己的代码。