我在.NET 4.5 C#组件中有一个异步方法:
public async Task<T> GetResultAsync()
{
return PerformOperationAsync();
}
如果PerformOperationAsync抛出异常,那么我可以在客户端捕获AggregateException,打开它并获取抛出的原始异常。
但是,如果我的代码稍微复杂一些:
public async Task<T> GetResultAsync()
{
return PerformOperationAsync().ContinueWith(x =>
{
var result = x.Result;
return DoSomethingWithResult(result);
}, cancellationToken);
}
...然后,如果发生异常,客户端会捕获嵌套的AggregateException,因此在获取原始版本之前必须将其展平。
是否应该避免这种行为,或者客户端是否需要预期可能嵌套的AggregateException并调用Flatten来解包其所有级别?如果组件开发人员应该避免这种行为,那么在ContinueWith场景中处理它的正确方法是什么?我有很多类似的情况,所以我试图找到最轻量级的处理方法。
答案 0 :(得分:4)
C#5 async / await将帮助您处理延续和正确的异常处理,同时简化代码。
public async Task<T> GetResultAsync()
{
var result = await PerformOperationAsync().ConfigureAwait(false);
return DoSomethingWithResult(result);
}
您的方法已标记为异步,是否有意?
要保持延续,您可以提供TaskContinuationOptions
OnlyOnRanToCompletion
值:
PerformOperationAsync().ContinueWith(x =>
{
var result = x.Result;
return DoSomethingWithResult(result);
}, TaskContinuationOptions.OnlyOnRanToCompletion);
或使用awaiter引发原始异常
PerformOperationAsync().ContinueWith(x =>
{
var result = x.GetAwaiter().GetResult();
return DoSomethingWithResult(result);
}, cancellationToken);
答案 1 :(得分:0)
除了Guillaume's答案之外,我还在使用一种扩展方法
public static class Ext
{
/// <summary>
/// Wait for task synchronously, then return result. Avoid AggregateExceptions
/// as it would be generated by asyncTask.Result.
/// </summary>
public static T SyncResult<T>(this Task<T> asyncTask)
=> asyncTask.GetAwaiter().GetResult();
}
代替var result = x.Result;
,像这样使用它:
var result = x.SyncResult();
它的作用与Guillaume相同,但使用时间较短且易于记忆。