Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 429|回复: 0

C#中异步编程异常的处理方式

[复制链接]
  • TA的每日心情
    奋斗
    2024-4-6 11:05
  • 签到天数: 748 天

    [LV.9]以坛为家II

    2034

    主题

    2092

    帖子

    70万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    705612
    发表于 2021-5-20 22:05:14 | 显示全部楼层 |阅读模式

    异步编程异常处理

     在同步编程中,一旦出现错误就会抛出异常,我们可以使用try…catch来捕捉异常,未被捕获的异常则会不断向上传递,形成一个简单而统一的错误处理机制。但是对于异步编程来说,异常处理一直是件麻烦的事情,所以接下来给大家介绍一下异步编程中的错误处理方式
    

    单个异常的捕获

     public static async Task ThrowExcrptionAsync(int ms, string message)
            {
                await Task.Delay(ms);
                throw new Exception(message);
            }
    
     public static async Task Main(string[] args)
            {
                
                try
                {
                   ThrowExcrptionAsync(2000, "first");
                }
                catch (Exception e)
                {
                   Console.WriteLine(e.Message);
                }
                Console.ReadKey();
            }
    

    如果调用以上的方法,并且没有等待,可以将异步方法放在try/catch中就可以捕获到异常,比如像上面一样调用ThrowExcrptionAsync方法,方法已经执行完毕,而throw new Exception(message)这句话还没执行,所以上面这段代码并不会捕获到异常

    注意:返回void的异步方法不会等待,这是因为从async void方法抛出的异常无法捕获,因此,异步方法最好返回一个Task类型。处理程序方法或重写的基类方法不受此规则限制

    异步方法异常的一个比较好的处理方式是使用await关键字,将其放在try/catch语句中,如以下代码琐事。异步调用ThrowExcrptionAsync方法后,主线程就会释放线程,但塔会在任务完成时保持任务的引用,此时(2s之后)会调用匹配的catch块内的代码

     public static async Task Main(string[] args)
            {
                
                try
                {
                await   ThrowExcrptionAsync(2000, "first");
                }
                catch (Exception e)
                {
                   Console.WriteLine(e.Message);
                }
                Console.ReadKey();
            }
    

    多个异常的捕获

     此时如果调用两个异步方法,每个方法都会抛出异常,我们该如何处理呢?如以下代码
    
     public static async Task Main(string[] args)
            {
                
                try
                {
                await   ThrowExcrptionAsync(2000, "first");
                await   ThrowExcrptionAsync(1000, "second");
                }
                catch (Exception e)
                {
                   Console.WriteLine(e.Message);
                }
                Console.ReadKey();
            }
    

    第一个ThrowExcrptionAsync被调用,2s抛出异常信息(包含信息first),该方法结束后,另一个ThrowExcrptionAsync方法也被调用,1s之后抛出异常,事实并非如此,因为第一个ThrowExcrptionAsync已经抛出了异常,try块内的代码块并没有继续调用第二个ThrowExcrptionAsync方法。而是直接进入catch块内的第一个异常进行处理,但是在现实编程中,这个并非我们所想。我们需要两个方法不管异常,都需要执行,而不是某一个报错直接跳出,所以我们使用WhenAll方法等待所有方法执行完成再catch(在外部定义两个task对象,用来接受我们要执行方法的结果),

     public static async Task Main(string[] args)
            {
                Task t1 = null;
                Task t2 = null;
                try
                {
                    t1 = ThrowExcrptionAsync(2000, "first");
                    t2 = ThrowExcrptionAsync(1000, "second");
                    await Task.WhenAll(t1, t2);
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                }
                Console.ReadKey();
            }
    

    这个时候,我们已经让两个方法都执行了。没有管内部的错误,接下来我们去捕获两个异常中的错误信息,代码如下

    public static async Task Main(string[] args)
            {
                Task t1 = null;
                Task t2 = null;
                try
                {
                    t1 = ThrowExcrptionAsync(2000, "first");
                    t2 = ThrowExcrptionAsync(1000, "second");
                    await Task.WhenAll(t1, t2);
                }
                catch (Exception e)
                {
                    if (t1.IsFaulted)
                    {
                        Console.WriteLine(t1.Exception.InnerException);
                    }
                    if (t2.IsFaulted)
                    {
                        Console.WriteLine(t2.Exception.InnerException);
                    }
                    Console.WriteLine(e.Message);
                }
                Console.ReadKey();
            }
    
    在这里我们使用的的是IsFaulted属性,该属性用来检查任务的状态,以确定它们是否为出错状态,若出现异常,IsFaulted属性会返回true。可以使用Task类中的Exception.InnerException来访问信息本身。当然,我们知道IsFaulted的状态后。肯定是可以进行别的业务逻辑处理的。
    
    另外还有一种比较快速获取task类中的异常信息的,代码如下:
    
    public static async Task Main(string[] args)
            {
                Task taskResult = null;
                try
                {
                    var t1 = ThrowExcrptionAsync(2000, "first");
                    var t2 = ThrowExcrptionAsync(1000, "second");
                    await (taskResult = Task.WhenAll(t1, t2));
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                    foreach (var item in taskResult.Exception.InnerExceptions)
                    {
                        Console.WriteLine(item.Message);
                    }
                }
                Console.ReadKey();
            }
    
    方法其实和上面的判断状态再去获取异常信息差不多,该方法主要是在日志中使用较多。
    

    如有哪里讲得不是很明白或是有错误,欢迎指正
    如您喜欢的话不妨点个赞收藏一下吧

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-5-4 08:35 , Processed in 0.073698 second(s), 29 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表