簡體   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