簡體   English   中英

異步方法異常的不同行為

[英]Different behavior of exception with async method

假設您有2個async方法定義如下:

public async Task<TResult> SomeMethod1()
{
    throw  new Exception();
}

public async Task<TResult> SomeMethod2()
{
    await Task.Delay(50);
    throw new Exception();
}

現在,如果await這兩種方法,行為將基本相同。 但是,如果你正在完成任務,行為是不同的。

如果我想緩存這樣的計算結果,但只有當任務運行完成時。 我必須照顧這兩種情況:

第一種情況:

public Task<TResult> CachingThis1(Func<Task<TResult>> doSomthing1)
{
    try
    {
       var futur = doSomthing1()
       futur.ContinueWith(
               t =>
               {
                  // ... Add To my cache
               },
               TaskContinuationOptions.NotOnFaulted);
    }
    catch  ()
    {
        // ... Remove from the pending cache
        throw;
    }
}

第二種情況

public Task<TResult> CachingThis2(Func<Task<TResult>> doSomthing)
{
    var futur = SomeMethod2();
    futur.ContinueWith(
       t =>
       {
           // ... Add To my cache
       },
       TaskContinuationOptions.NotOnFaulted);
    futur.ContinueWith(
       t =>
       {
          // ... Remove from the pending cache
       },
       TaskContinuationOptions.OnlyOnFaulted);
}

現在我將執行計算緩存的方法傳遞給我的緩存系統。

cachingSystem.CachingThis1(SomeMethod1);
cachingSystem.CachingThis2(SomeMethod2);

顯然,我需要在“ ConinueWith on ConinueWith ”和catch塊中復制代碼。 你知道是否有辦法使異常行為相同,無論是在await之前還是之后?

SomeMethod1SomeMethod2所需的異常處理沒有區別。 它們以完全相同的方式運行,異常將存儲在返回的任務中。

這個例子很容易看出來;

static void Main(string[] args)
{
    try
    {
        var task = SomeMethod1();
    }
    catch
    {
        // Unreachable code
    }
}

public static async Task SomeMethod1()
{
    throw new Exception();
}

在這種情況下不會處理任何異常,因為不等待返回的任務。

但是,簡單的Task -returning方法和async方法之間存在區別:

public static Task TaskReturning()
{
    throw new Exception();
    return Task.Delay(1000);
}

public static async Task Async()
{
    throw new Exception();
    await Task.Delay(1000);
}

您可以通過簡單地使用async包裝器方法來避免代碼重復,該方法既可以調用方法,也可以在單個try-catch塊中await返回的任務:

public static async Task HandleAsync()
{
    try
    {
        await TaskReturning();
        // Add to cache.
    }
    catch
    {
        // handle exception from both the synchronous and asynchronous parts.
    }
}

除了I3arnon在他的回答中所說的,如果您在沒有指定的TaskContinuationOptions情況下ContinueWith使用異步方法,則可以通過以下方式處理在延遲處理程序中接收的Task參數捕獲的異常:

SomeMethod1().ContinueWith(ProcessResult);
SomeMethod2().ContinueWith(ProcessResult);

使用ProcessResult處理程序,如下所示:

private void ProcessResult<TResult>(Task<TResult> task)
{
    if (task.IsFaulted)
    {
        //remove from cahe
    }
    else if (task.IsCompleted)
    {
        //add to cache
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM