我们在C#的try catch代码块中里面经常使用throw语句抛出捕捉到的异常,但是你知道吗使用throw ex和throw抛出捕获到的异常效果是不一样的。

异常捕捉的原理

首先先介绍一下C#异常捕捉的原理,默认情况下在C#的一个函数中(注意这里说的是在一个函数中,不是跨多个函数),只会将最后一个异常抛出的位置记录到异常堆栈中,也就是说在一个函数中无论你用throw语句抛出了多少次异常,异常堆栈中始终记录的是函数最后一次throw异常的位置,如下面代码的函数ThrowExceptionFunction中使用throw语句抛出了4次异常,但是在46行的代码处只显示函数ThrowExceptionFunction在32行抛出了异常,之前抛出的3次异常都没有被记录到异常堆栈之中。

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace ExceptionTest2
{
class Program
{
static void ThrowExceptionFunction()
{
try
{
try
{
try
{
throw new Exception("模拟异常");
}
catch (Exception ex1)
{
throw;
}
}
catch (Exception ex2)
{
throw;
}
}
catch (Exception ex3)
{
throw;
} } static void Main(string[] args)
{
try
{
ThrowExceptionFunction();
}
catch (Exception ex)
{
Console.WriteLine(ex.StackTrace);//因为C#会为每个函数的异常记录一次堆栈信息,而本例中有两个函数分别为ThrowExceptionFunction和Main,所以这里堆栈捕捉到了两个异常一个是在函数ThrowExceptionFunction中32行,另一个是Main函数中42行,
} Console.ReadLine();
}
}
}

在.net framework3.5及之前,函数中catch代码块抛出的异常无法准确捕捉到位置,如下面代码中Main函数最后一次抛出异常是在代码20行,但是在25行输出的信息中却显示异常是在代码29行抛出的,这应该是.net framework3.5及之前的一个BUG,在.net framework4.0中已经修复了这个问题。

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace ExceptionTest3
{
class Program
{
static void Main(string[] args)
{
try
{
try
{
throw new Exception("异常模拟");
}
catch (Exception ex1)
{
throw;
}
}
catch (Exception ex2)
{
Console.WriteLine(ex2.StackTrace);
} Console.ReadLine();
}
}
}

上面我们说了C#只会将一个函数中最后一次抛出异常的位置记录到异常堆栈之中,那么有什么办法能将一个函数中抛出的所有异常都记录到异常堆栈中吗?答案是可以的,构造嵌套异常即可,如下代码所示:

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace ExceptionTest4
{
class Program
{
static void ThrowExceptionFunction()
{
try
{
try
{
try
{
throw new Exception("模拟异常1");
}
catch (Exception ex1)
{
throw new Exception("模拟异常2", ex1);
}
}
catch (Exception ex2)
{
throw new Exception("模拟异常3", ex2);
}
}
catch (Exception ex3)
{
throw new Exception("模拟异常4", ex3);
} } static void Main(string[] args)
{
try
{
ThrowExceptionFunction();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());//要想输出函数ThrowExceptionFunction内抛出的所有异常,将ThrowExceptionFunction内部的异常都嵌套封装即可,然后在输出异常的时候使用ex.ToString()函数,就可以输出所有嵌套异常的堆栈信息
} Console.ReadLine();
}
}
}

上面代码中我们在函数ThrowExceptionFunction中将四个throw出来的异常都嵌套封装了,最后在Main函数中使用ex.ToString()函数即可输出完整的异常堆栈,在ThrowExceptionFunction函数中抛出的所有异常都显示在了ex.ToString()函数输出的堆栈列表之中。

throw ex和throw

我们知道在try catch的catch代码块捕捉到异常之后可以使用throw ex和throw将捕捉到的异常再抛出来,那么这两种写法有什么不同呢?

throw ex

throw ex这种写法会让C#重置异常的抛出点,我们来看这段代码:

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace ExceptionTesting
{
class Program
{
static void InnerException()
{
throw new Exception("模拟异常");
} static void OuterException()
{
try
{
InnerException();
}
catch (Exception ex)
{
throw ex;
}
} static void Main(string[] args)
{
try
{
OuterException();
}
catch (Exception ex)
{
Console.WriteLine(ex.StackTrace);//由于代码24行使用throw ex重置了异常抛出点,所以这里异常堆栈只能捕捉到代码32行和24行抛出的异常,但是13行的异常在堆栈中无法捕捉到
} Console.ReadLine();
}
}
}

可以看到使用throw ex会使得C#重置代码中异常的抛出点,从而让C#认为异常的原始抛出点应该是在代码24行,在异常堆栈中无法捕捉到代码13行所抛出的异常。

throw

使用throw和throw ex唯一的不同就是throw并不会让C#重置异常的抛出点,我们将上面代码中24行的throw ex改为throw如下:

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace ExceptionTesting
{
class Program
{
static void InnerException()
{
throw new Exception("模拟异常");
} static void OuterException()
{
try
{
InnerException();
}
catch(Exception ex)
{
throw;
}
} static void Main(string[] args)
{
try
{
OuterException();
}
catch(Exception ex)
{
Console.WriteLine(ex.StackTrace);//由于现在代码24行使用了throw抛出捕获到的异常,并没有重置原始异常的抛出点,所以这里异常堆栈不但能捕捉到代码32行和24行抛出的异常,还能捕捉到代码13行抛出的异常。
} Console.ReadLine();
}
}
}

由于这一次我们使用了throw来抛出代码24行中catch代码块中捕获到的异常,并没有重置异常的抛出点,因此在上面代码36行这一次异常堆栈输出了13行、24行、32行三个异常。

C#中try catch中throw ex和throw方式抛出异常有何不同的更多相关文章

  1. C#中try catch中throw ex和throw方式抛出异常有何不同_异常捕获堆栈丢失问题

    前言,最近遇到一个使用try-catch异常捕获后记录一下日志,然后再抛出该异常后,异常堆栈里无法显示准确的堆栈地址的问题?   其实以前也遇到过类似问题,没有重视,这次好好研究了下,并上度娘上找了找 ...

  2. C++中Try Catch中的继承

    1.C++中Try Catch简介:我们编译运行程序出错的时候,编译器就会抛出异常.抛出异常要比终止程序灵活许多. 而C++异常是指在程序运行时发生的反常行为,这些行为超出了函数正常功能的范围.当程序 ...

  3. c++中try catch的用法

    c++中try catch的用法 标签: c++exception数据库sqlc 2011-10-24 21:49 45622人阅读 评论(3) 收藏 举报  分类: 一点小结(267)  版权声明: ...

  4. C#:在catch中return,会执行finally吗?

    本文转自 vipxiaotian(CSDN) 请参考下面一段简单的语句块: 1:  try2:  {3:      throw new Exception("new exception&qu ...

  5. C#中try catch finally的执行顺序

    1.首先明确一点,就是不管怎样,finally一定会执行,即使程序有异常,并且在catch中thorw 了 ,finally还是会被执行. 2.当try和catch中有return时,finally仍 ...

  6. javascript中 try catch用法

    javascript中 try catch用法 投稿:hebedich 字体:[增加 减小] 类型:转载 时间:2015-08-16我要评论 JS try catch语句一般在什么情况下使用?是必须使 ...

  7. Java中try catch finally的执行顺序问题

    finally 语句块是在 try 或者 catch 中的 return 语句之前执行的.更加一般的说法是,finally 语句块应该是在控制转移语句之前执行,控制转移语句除了 return 外,还有 ...

  8. java中try{}catch{}和finally{}的执行顺序问题

     今天我给大家讲解一下java的的错误和异常处理机制以及相关异常的执行顺序问题.如有不足的地方,欢迎批评指正~ 1.首相简单介绍一下java中的错误(Error)和异常(Exception) 错误和异 ...

  9. Java中try,catch,finally的用法

    Java中try,catch,finally的用法,以前感觉还算熟悉,但看到一篇博文才有更深点的理解,总结网友博客如下. Java异常处理的组合方式: 1.try+catch  运行流程:运行到try ...

随机推荐

  1. 【转】安装第三方库出现 Python version 2.7 required, which was not found in the registry

    安装第三方库出现 Python version 2.7 required, which was not found in the registry 建立一个文件 register.py 内容如下. 然 ...

  2. 如何获取hibernate代理类代理的实际对象实例?

    在hibernate中,通过sql语句查询带clob字段的记录,查出来的结果集是List<HashMap<String,Object>>类型,在调用jackson的接口转为js ...

  3. 开发中容易写错的一条SQL语句

    select * from tableName where name = like '%糖糖%' 出错的地方:name后面有=和like 出错的原因:复制过来的,其它地方是=,没有删掉直接加了like ...

  4. ExAllocatePool、ExAllocatePoolWithTag

    PVOID p = ExAllocatePool(Pool_Type, Size); PVOID p = ExAllocatePoolWithTag(Pool_Type, Size, Tag); 调用 ...

  5. php实现网页trace方法

    // 记录内存初始使用和开始时间,在系统的入口记录 $beginTime= microtime(TRUE); $start_memory = memory_get_usage(); //die; ec ...

  6. 模拟jquery的$()选择器的实现

    <html> <head> </head> <body> <div id="div1">div1</div> ...

  7. 采用DBCP连接池技术管理连接

    DBCP的使用步骤步骤一:导包,使用第三方的道具,必须导入相应的jar包. 一般需要导入两个jar包: -commons-dbcp-1.x.jar包 -commons-pool-1.x.x.jar包 ...

  8. Activiti-explorer 在tomcat中部署报HTTP Status 404问题

    如果tomcat版本没错,请检查一下文件,将Activiti中war文件夹中的内容复制到webapp下,而不是将文件夹整个放进去……

  9. chrome 'adobe flash player 已过期'解决方法

    http://labs.adobe.com/downloads/flashplayer.html下载 WindowsDownload Flash Player for Opera and Chromi ...

  10. shell (check return of each line)and sudoer

    shell result from cmdline echo $? if 0 then success ;else failure (shell 执行每部返回值,rm -rf 错误,打包不能覆盖) 解 ...