• 在finally中调用一个需要await的方法


      最近在把code改写成async+await的形式,发现有些情况下需要在finally中需要调用异步方法,但是编译器不允许在cache和finally中出现await关键字。。。但是用Wait()或者Result又会导致一些其他稀奇古怪的毛病(死锁啦,AggregateException啦。。。)

      所以,需要找一个类似于finally的效果,并且允许使用async..await的方式,想了一下,其实这不就是ContinueWith么!

      对没有返回值的try..finally可以用下面的方法:

    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了。

      来看下使用的示例:

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

      但是如果有TryPart返回值哪?于是我们需要这样的一个重载:

    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。

      最后,finallyCode里面也要当心一个陷阱,不要随便看tryCode.Result,有可能里面是个异常!

  • 相关阅读:
    Innodb中自增长值的列
    LINUX-vmstat命令讲解
    find命令总结
    特殊权限chattr的用法
    openstack的最简单安装
    解决新电脑的系统安装问题:针对BIOS的UEFI模式
    Linux中安装字体
    云主机和vps的区别
    install-scp
    常见typedef 用法
  • 原文地址:https://www.cnblogs.com/vwxyzh/p/3924483.html
Copyright © 2020-2023  润新知