我们在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. HDU2438 数学+三分

    Turn the corner Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)T ...

  2. jQuery用法小结

    jQuery加载1.$(document).ready()2.添加css样式:单个:$("p").css("color","red"); 多 ...

  3. Moneybookers API支付方式开发 步骤

    开发文档: 支付说明手册 步骤: 1.使用商家帐号,登录到www.moneybookers.com,核对商家信息是否正确. 2.在账户-->商家工具(设置) a.API/MQI password ...

  4. DBUtils

    DBUtils中核心对象 > QueryRunner类 它提供了操作数据增删改查的方法 query() 执行select语句的 update() 执行insert update delete 语 ...

  5. 2017技术核心——Spring

    从毕业从事Java WEB开始到现在已差不多快5年时间了,一直使用的Spring相关的技术,其实最主要的是SpringMVC这一块.其实,一直停留在用的地步,并不知晓其原理,真正耐下心来去研究Spri ...

  6. juqery 拖拽元素

    转自  http://www.cnblogs.com/holbrook/archive/2012/03/13/2394111.html 因为怕博主删除博客,所以复制过来! JQuery UI是JQue ...

  7. node-webkit 桌面开发 初入1

    node-webkit  是什么就不介绍了 注意官网的一句话 ”node-webkit is based on Chromium and node.js " 所以node-webkit 实际 ...

  8. js弹出框,禁刷新

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  9. 怎么搭建DC+SCCM 域环境(一)

    需要的软件: 1. SCCM 2012 SP1 2. SQL Server 2012 3. System ISO 4. ADK 环境搭建顺序: 1. 安装DC和SCCM 机器,并配置需要的IP.DNS ...

  10. oracle中merge方法

    先看SQL语句:merge into employee e using emps em on (e.emp_id=em.emp_id) when matched then  update set e. ...