繁体   English   中英

使用 Task.ContinueWith 时如何避免嵌套的 AggregateException?

[英]How to avoid nested AggregateException when using Task.ContinueWith?

我在 .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 场景中处理它的正确方法是什么? 我有很多类似的情况,所以我试图找到处理它们的最轻量级的方法。

C#5 async/await 将帮助您处理延续和适当的异常处理,同时简化代码。

public async Task<T> GetResultAsync()
{
    var result = await PerformOperationAsync().ConfigureAwait(false);
    return DoSomethingWithResult(result);
}

您的方法已被标记为异步,是有意的吗?


为了保持延续,您可以提供一个TaskContinuationOptionsOnlyOnRanToCompletion值:

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);

除了纪尧姆的回答,我使用了一点扩展方法

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解释的相同,但使用时间更短且更易于记忆。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM