在finally中調用一個須要await的方法

  最近在把code改寫成async+await的形式,發現有些狀況下須要在finally中須要調用異步方法,可是編譯器不容許在cache和finally中出現await關鍵字。。。可是用Wait()或者Result又會致使一些其餘稀奇古怪的毛病(死鎖啦,AggregateException啦。。。)異步

  因此,須要找一個相似於finally的效果,而且容許使用async..await的方式,想了一下,其實這不就是ContinueWith麼!async

  對沒有返回值的try..finally能夠用下面的方法:this

public static async Task WithFinally(this Task tryCode, Func<Task, Task> finallyCode)
{
  await await tryCode.ContinueWith(finallyCode);
}

  爲何是await await?這個問題要說下ContinueWith的返回值了,ContinueWith(Action<Task>)返回Task,因此只須要一個await。而ContinueWith(Func<Task, TResult>返回的是Task<TResult>,這裏TResult是Task,因此,返回值是Task<Task>,await Task<Task>,獲得的是另外一個Task,顯然任務還沒跑完,接着再等這個Task,就有了兩個await了。spa

  來看下使用的示例:code

async Task Sample()
{
   // do something ...
   await TryPart().WithFinally(async task =>
   {
      // do something ...
      await AsyncCallInFinally();
      // do something ...
   });
   // do something ...
}
Task TryPart()
{
   // ...
}
Task AsyncCallInFinally()
{
   // ...
}

  可是若是有TryPart返回值哪?因而咱們須要這樣的一個重載:blog

public static async Task<TResult> WithFinally<TResult>(this Task<TResult> tryCode, Func<Task<TResult>, Task> finallyCode)
{
   await await tryCode.ContinueWith(finallyCode);
   return await tryCode;
}

  這裏假設finally部分不修改try部分的放回值。代碼裏除了以前的那個await await以外,又加了個return await tryCode,這裏爲何要用await tryCode而不是用tryCode.Result哪?編譯器

  還記得前面說的那些稀奇古怪的毛病麼?雖然這裏用Result不可能出現死鎖(前面的await await已經能夠保證finallyCode執行完,finallyCode又是在tryCode完成後跑的,因此此時tryCode必定完成了),可是別忘了在出錯的狀況下,二者是有區別的,await tryCode會拋出原來tryCode中的異常,而tryCode.Result會拋出AggregateException。it

  最後,finallyCode裏面也要小心一個陷阱,不要隨便看tryCode.Result,有可能裏面是個異常!io

相關文章
相關標籤/搜索