我们在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. 大数据技术Hadoop入门理论系列之一----hadoop生态圈介绍

    Technorati 标记: hadoop,生态圈,ecosystem,yarn,spark,入门 1. hadoop 生态概况 Hadoop是一个由Apache基金会所开发的分布式系统基础架构. 用 ...

  2. 06@LabVIEW发布功能总结

    前言 在没有接触到LabVIEW强大的发布功能前,我时常发愁如何把自己的工具包给别人装上,有时候为了一些特定的安装,需要自己写一个一键安装的程序,时间长了发现还不如直接复制来的快,就是苦了那些用工具包 ...

  3. Java学习_int和Integer的区别+包装类

    1.Java 中的数据类型分为基本数据类型和引用数据类型 int是基本数据类型,Integer是引用数据类型: Ingeter是int的包装类,int的初值为0,Ingeter的初值为null. 2. ...

  4. Unity Aspect

    Unity封装的东西太多,所以在很多情况下回忽略这些基本的事情.游戏窗口的中Aspect是通过Game窗口中进行选择,但对于相机的Aspect Unity并没有暴露接口在设置界面中,至少在编辑器下进行 ...

  5. 【转】WiFi基础知识

    http://blog.csdn.net/myarrow/article/details/7930131 1. IE802.11简介 标准号 IEEE 802.11b IEEE 802.11a IEE ...

  6. 另一种在WINFORM中使用XNA的方法

    之前在写化学分子模型制作程序的时候,使用一种方法,将WINFORM控件嵌入到XNA窗体中,从而实现了即使用WINFORM窗体控件又使用XNA.最近在写另一个物理运动学课件制作程序,同样使用XNA,但从 ...

  7. VS2013自带的Browser Link功能引发浏览localhost网站时不停的轮询

    浏览localhost网站时候不管你打开那个页面它都会不停的轮询.据悉这是VS2013自带的Browser Link功能,里面用到SignalR机制 什么是Browser Link功能,什么是Sign ...

  8. 1.Linux是什么?

    UNIX设计理念: 所有的程序或系统装置都是文件. 不管构建编辑器还是附属文件,所写的程序只有一个目的,就是有效地完成目标 操作系统:应用程序->系统调用->内核->硬件.其中系统调 ...

  9. docker在centos7下的一些坑

    在centos的docker上安装mysql提示chown mod /var/lib/mysql permission denied,通过下面的方法1解决. 在centos上挂载数据卷,在容器内部访问 ...

  10. Android 自定义spinner下拉框实现

    一:前言本人参考博客:http://blog.csdn.net/jdsjlzx/article/details/41316417 最近在弄一个下拉框,发现Android自带的很难实现我的功能,于是去网 ...