在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

相关文章
相关标签/搜索