C#中异步编程异常的处理方式
异步编程异常处理
在同步编程中,一旦出现错误就会抛出异常,我们可以使用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();
}
方法其实和上面的判断状态再去获取异常信息差不多,该方法主要是在日志中使用较多。
如有哪里讲得不是很明白或是有错误,欢迎指正
如您喜欢的话不妨点个赞收藏一下吧
C#中异步编程异常的处理方式的更多相关文章
- Java 异步编程的几种方式
前言 异步编程是让程序并发运行的一种手段.它允许多个事情同时发生,当程序调用需要长时间运行的方法时,它不会阻塞当前的执行流程,程序可以继续运行,当方法执行完成时通知给主线程根据需要获取其执行结果或者失 ...
- 谈谈c#中异步编程模型的变迁
大家在编程过程中都会用到一些异步编程的情况.在c#的BCL中,很多api都提供了异步方法,初学者可能对各种不同异步方法的使用感到迷惑,本文主要为大家梳理一下异步方法的变迁以及如何使用异步方法. Beg ...
- Web worker 与JS中异步编程的对比
0.从一道题说起 var t = true; setTimeout(function(){ t = false; }, 1000); while(t){ } alert('end'); 问,以上代码何 ...
- JavaScript中异步编程
一 关于事件的异步 事件是JavaScript中最重要的一个特征,nodejs就是利用js这一异步而设计出来的.所以这里讲一下事件机制. 在一个js文件中,如果要运行某一个函数,有2中手段,一个就是直 ...
- 你不知道的JavaScript--Item27 异步编程异常解决方案
1.JavaScript异步编程的两个核心难点 异步I/O.事件驱动使得单线程的JavaScript得以在不阻塞UI的情况下执行网络.文件访问功能,且使之在后端实现了较高的性能.然而异步风格也引来了一 ...
- Java网络编程中异步编程的理解
目录 前言 一.异步,同步,阻塞和非阻塞的理解 二.异步编程从用户层面和框架层面不同角度的理解 用户角度的理解 框架角度的理解 三.为什么使用异步 四.理解这些能在实际中的应用 六.困惑 参考文章 前 ...
- c#中异步编程
异步是现实生活中的很多现象的一种抽象.比如分工合作在很多时间段就是异步合作.异步中也一般要涉及委托方法.c#有3种模式的异步编程:异步模式,基于事件的异步模式,基于任务的异步模式(TAP). 一. ...
- Java 异步编程 (5 种异步实现方式详解)
同步操作如果遇到一个耗时的方法,需要阻塞等待,那么我们有没有办法解决呢?让它异步执行,下面我会详解异步及实现@mikechen 目录 什么是异步? 一.线程异步 二.Future异步 三.Comp ...
- promise 的基本概念 和如何解决js中的异步编程问题 对 promis 的 then all ctch 的分析 和 await async 的理解
* promise承诺 * 解决js中异步编程的问题 * * 异步-同步 * 阻塞-无阻塞 * * 同步和异步的区别? 异步;同步 指的是被请求者 解析:被请求者(该事情的处理者)在处理完事情的时候的 ...
随机推荐
- window、BOM、 document、 DOM
window: 顾名思义,窗口,浏览器窗口.是Window构造函数的一个实例对象. 它包含浏览器的一些属性和方法,如screen,location,history,setInterval等. // ...
- 创建全局变量用以保存传递MFC中不同窗口中的数据
格式如下: //DATA_TEMP.h class CDATA_TEMP{public: CDATA_TEMP(); virtual ~CDATA_TEMP();public: static int ...
- CodeForces - 999C Alphabetic Removals
C - Alphabetic Removals ≤k≤n≤4⋅105) - the length of the string and the number of letters Polycarp wi ...
- css偷懒神奇
偷懒神奇链接:https://qishaoxuan.github.io/css_tricks/glass/
- Java实现线程的三种方式和区别
Java实现线程的三种方式和区别 Java实现线程的三种方式: 继承Thread 实现Runnable接口 实现Callable接口 区别: 第一种方式继承Thread就不能继承其他类了,后面两种可以 ...
- 拆分项目搞成framework 实例
目前工作中遇到的问题,是讲项目三大模块拆分, 将Discover.Shop和Events的源代码拆分到独立的项目中 拆分是个麻烦事,里面相互依赖很多 ,打包编译也异常复杂,各种报错 编译Event 遇 ...
- spring boot 学习常用网站
springboot的特性 https://www.cnblogs.com/softidea/p/5644750.html 1.自定义banner https://www.cnblogs.com/cc ...
- idea 使用maven 下载源码包
方式1:全量下载源码包 方式二:下载单个源码包 随便找个源码可以看到文件上有download (标识下载源码包) choose sources表示选择那个版本的源码包
- centos7 安装 mysql(在线安装)
在CentOS中默认安装有MariaDB,这个是MySQL的分支,但为了需要,还是要在系统中安装MySQL,而且安装完成之后可以直接覆盖掉MariaDB. 1 下载并安装MySQL官方的 Yum Re ...
- 跨平台(win和unix)的线程封装类
#ifdef WIN32 #include <Windows.h> #include <process.h> #else #include <pthread.h> ...