c# 基于任务的异步编程模式(TAP)的异常处理

 更新时间:2020年11月02日 09:08:42   作者:一只独行的猿  
这篇文章主要介绍了c# 基于任务的异步编程模式的异常处理方法,帮助大家更好的理解和学习c#

在前面讲到了《基于任务的异步编程模式(TAP)》,但是如果调用异步方法,没有等待,那么调用异步方法的线程中使用传统的try/catch块是不能捕获到异步方法中的异常。因为在异步方法执行出现异常之前,已经执行完毕。

1、没有等待的调用异步方法

ThrowAfter方法是在一定延迟后抛出一个异常:

private async Task ThrowAfter(int ms,string message)
{
  await Task.Delay(ms);
  Console.WriteLine("异步任务随后将抛出异常。");
  throw new Exception(message);
}

DontHandle方法在调用异步方法时,由于有滞后性,所以使用try...catch...不能捕获到异步方法中的异常。

public void DontHandle()
{
  try
  {
    ThrowAfter(200, "异步方法抛出的异常");
  }
  catch(Exception ex)
  {
    Console.WriteLine(ex.Message);
  }
  Console.WriteLine("完成方法:DontHandle");
}

注意:返回void的异步方法不会等待。因为从async void方法抛出的异常无法捕获。因此,异步方法最好返回一个Task类型。

2、异步方法的异常处理

异步方法异常的比较好的处理方式使使用await关键字,将其放在try/catch语句中。

public async void HandleOneError()
{
  Console.WriteLine("HandleOneError方法开始执行。。。");
  try
  {
    await ThrowAfter(2000, "异步方法抛出的异常");
  }
  catch (Exception ex)
  {
    Console.WriteLine(ex.Message);
  }
  Console.WriteLine("完成方法:HandleOneError");
}

调用ThrowAfter方法后,HandleOneError会释放线程,但它会在任务完成时保持对任务的引用。当异步方法抛出异常,会调用匹配的catch块内的代码。

3、多个异步方法的异常处理

如果调用多个异步方法,会有多个抛出异常,在捕获异常时就会有问题。

public async void StartTwoTasks()
{
  Console.WriteLine("StartTwoTasks方法开始执行。。。");
  try
  {
    await ThrowAfter(2000, "first");//先执行该方法
    await ThrowAfter(1000, "Second");//第一个异步方法正常执行完后才会执行该方法
  }
  catch(Exception ex)
  {
    Console.WriteLine(ex.Message);
  }
  Console.WriteLine("完成方法:StartTwoTasks");
}

StartTwoTasks方法中,调用了两个异步方法。理论上认为,当第一个异步方法执行完,抛出异常后,紧接着就会调用第二个异步方法,并抛出异常。但实际上是第一个异步方法抛出异常之后,就会被catch捕获,并不会执行第二个异步方法。因为这种类型中,在“基于任务的异步编程模式(TAP)”一文中解释过,这种调用方法是等待第一个异步方法执行结束后,调用函数的线程控制权才会调用第二个异步方法,多个异步方法以此类推。但是当时我们使用了Task类中的WhenAll方法同时等待多个任务全部执行完,才执行后面的代码。

public async void StartTwoTasksParallel()
{
  Console.WriteLine("StartTwoTasksParallel方法开始执行。。。");
  try
  {
    Task t1 = ThrowAfter(2000, "first");//先执行该方法
    Task t2 = ThrowAfter(1000, "Second");//第一个异步方法执行完后才会执行该方法
    await Task.WhenAll(t1, t2);
  }
  catch (Exception ex)
  {
    Console.WriteLine(ex.Message);
  }
  Console.WriteLine("完成方法:StartTwoTasksParallel");
}

StartTwoTasksParallel方法使用Task类的WhenAll方法,并行调用两个不关联的异步方法。该方法将等待所有任务结束后才结束调用,不论任何一个抛出异常都不会影响其他任务。但是,该方法只会捕获第一个异常(先抛出异常的任务),其他异常将不会被显示。

有一种方法可以获取所有任务的异常信息,就是在try块外声明任务变量t1和t2,让这两个变量在catch块内访问。在catch块中检测任务的IsFaulted属性确认任务的状态,以判定是否出现异常,然后通过Task类的Exception.InnerException访问异常信息本身。

4、使用AggregateException信息

Task.WhenAll方法返回一个Task的结果变量。catch语句只会捕捉到所有异步任务中的第一个异常,但是Task.WhenAll方法返回的Task类型结果变量中会包含所有任务都出现的异常。外部结果任务的Exception属性是一个AggregateException类型,显示所有异常只需要遍历结果任务中的Exception的InnerExceptions属性即可。

public async void ShowAggregatedException()
{
  Console.WriteLine("ShowAggregatedException方法开始执行。。。");
  Task taskResult = null;
  try
  {
    Task t1 = ThrowAfter(2000, "first");//先执行该方法
    Task t2 = ThrowAfter(1000, "second");//第一个异步方法执行完后才会执行该方法
    Task t3 = ThrowAfter(1500, "third");//第一个异步方法执行完后才会执行该方法
    await (taskResult = Task.WhenAll(t1, t2, t3));
  }
  catch (Exception ex)
  {
    Console.WriteLine("handle {0}",ex.Message);
    foreach (Exception ex1 in taskResult.Exception.InnerExceptions)
    {
      Console.WriteLine("Inner exception {0}", ex1.Message);
    }
  }
  Console.WriteLine("完成方法:ShowAggregatedException");
}

以上就是c# 基于任务的异步编程模式(TAP)的异常处理的详细内容,更多关于c# 异步编程的资料请关注脚本之家其它相关文章!

相关文章

  • C#探秘系列(一)——ToDictionary,ToLookup

    C#探秘系列(一)——ToDictionary,ToLookup

    这个系列我们看看C#中有哪些我们知道,但是又不知道怎么用,又或者懒得去了解的东西,比如这篇我们要介绍的toDictionary和ToLookup。
    2014-05-05
  • 游戏开发之随机概率的选择算法

    游戏开发之随机概率的选择算法

    这篇文章主要介绍了游戏开发之随机概率的选择算法,需要的朋友可以参考下
    2015-07-07
  • C#中反射和扩展方法如何运用

    C#中反射和扩展方法如何运用

    这篇文章主要为大家详细介绍了C#中反射和扩展方法的运用,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-05-05
  • C#如何控制IIS动态添加删除网站详解

    C#如何控制IIS动态添加删除网站详解

    这篇文章主要给大家介绍了关于C#如何控制IIS动态添加删除网站的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用C#具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-11-11
  • c#利用Excel直接读取数据到DataGridView

    c#利用Excel直接读取数据到DataGridView

    这个例子的功能是c#读取excel文件,大家可以参考使用
    2013-11-11
  • C# Hashtable/Dictionary写入和读取对比详解

    C# Hashtable/Dictionary写入和读取对比详解

    本文中将从基础角度讲解HashTable、Dictionary的构造和通过程序进行插入读取对比
    2013-11-11
  • 浅谈C# AOP的简单实现

    浅谈C# AOP的简单实现

    这篇文章主要介绍了浅谈C# AOP的简单实现,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-07-07
  • 详解C# Lazy Loading(延迟加载)

    详解C# Lazy Loading(延迟加载)

    这篇文章主要介绍了C# Lazy Loading(延迟加载)的相关资料,帮助大家更好的理解和学习使用c#,感兴趣的朋友可以了解下
    2021-04-04
  • C#编写SqlHelper类

    C#编写SqlHelper类

    在C#中使用ADO.NET连接数据库的时候,每次连接都要编写连接,打开,执行SQL语句的代码,很麻烦,编写一个SqlHelper类,把每次连接都要写的代码封装成方法,把要执行的SQL语句通过参数传进去,可以大大简化编码
    2017-09-09
  • c#之用户定义的数据类型转换介绍

    c#之用户定义的数据类型转换介绍

    c#允许定义自己的数据类型,这意味着需要某些工具支持在自己的数据类型间进行数据转换。方法是把数据类型转换定义为相关类的一个成员运算符,数据类型转换必须声明是隐式或者显式,以说明怎么使用它
    2014-01-01

最新评论