refer:http://weblogs.asp.net/fmarguerie/archive/2008/01/02/rethrowing-exceptions-and-preserving-the-full-call-stack-trace.aspx

http://geekswithblogs.net/sdorman/archive/2007/08/20/Difference-between-quotthrowquot-and-quotthrow-exquot-in-.NET.aspx

Did you know that depending on the way you rethrow exceptions you may lose important information? There are already several blog posts that explain and demonstrate the difference between throw and throw ex. I'm realizing only now that none of the two solutions yields the complete call stack trace information!

Let's see what the problem is and I'll show you the real solution.

I'll use the following method to generate an exception:

private static void BadWork()
{
  int i = 0;
  int j = 12 / i; // Line 10: DivideByZeroException
  int k = j + 1;
}

Let's consider what happens if we call BadWork and rethrow the exception with throw ex as follows:

try
{
  BadWork();
}
catch (Exception ex)
{
  // do something
  // ...
  throw ex; // Line 24
}

Here is the call stack trace that we get in this case:

Unhandled Exception: System.DivideByZeroException: Attempted to divide by zero.
   at Program.WithThrowEx() in Program.cs:line 24
   at Program.Main(String[] args) in Program.cs:line 88

Line 24 is where throw ex is, not where the exception was thrown.

Let's now replace throw ex by throw:

try
{
  BadWork();
}
catch
{
  // do something
  // ...
  throw; // Line 38
}

This time, here is the call stack trace:

Unhandled Exception: System.DivideByZeroException: Attempted to divide by zero.
   at Program.BadWork() in Program.cs:line 10
   at Program.WithThrow() in Program.cs:line 38
   at Program.Main(String[] args) in Program.cs:line 89

As you can see, we get one additional stack frame this time. Line 10 is where the exception was thrown, which is important information because this is the only information that identifies where the exception actually happened.

This shows that it's better to use throw rather than throw ex if you want the full stack trace information to be preserved. However, there are cases where throw is not enough. In the following example, throw does not preserve the full stack trace:

try
{
  int i = 0;
  int j = 12 / i; // Line 47
  int k = j + 1;
}
catch
{
  // do something
  // ...
  throw; // Line 54
}

Unhandled Exception: System.DivideByZeroException: Attempted to divide by zero.
   at Program.WithThrowIncomplete() in Program.cs:line 54
   at Program.Main(String[] args) in Program.cs:line 106

This time, you can see that information is lost again. Line 54 is where throw is, not where the exception was thrown.

To preserve the full call stack information, you need to use the following method:

private static void PreserveStackTrace(Exception exception)
{
  MethodInfo preserveStackTrace = typeof(Exception).GetMethod("InternalPreserveStackTrace",
    BindingFlags.Instance | BindingFlags.NonPublic);
  preserveStackTrace.Invoke(exception, null);
}

This method can be used as follows:

try
{
  int i = 0;
  int j = 12 / i; // Line 78
  int k = j + 1;
}
catch (Exception ex)
{
  // do something
  // ...
  PreserveStackTrace(ex);
  throw; // Line 86
}

Here is the new call stack information you get with the above code:

Unhandled Exception: System.DivideByZeroException: Attempted to divide by zero.
   at Program.WithThrowAndStackTracePreservation() in Program.cs:line 78
   at Program.WithThrowAndStackTracePreservation() in Program.cs:line 86
   at Program.Main(String[] args) in Program.cs:line 110

Here is the call stack information you get with throw ex and a call to PreserveStackTrace:

Unhandled Exception: System.DivideByZeroException: Attempted to divide by zero.
   at Program.BadWork() in Program.cs:line 10
   at Program.WithThrowExAndStackTracePreservation() in Program.cs:line 62
   at Program.WithThrowExAndStackTracePreservation() in Program.cs:line 69
   at Program.Main(String[] args) in Program.cs:line 109

Here we get the full call stack information. Lines 78 and 10 are where the exceptions were thrown. To my knowledge, this is the only way to get complete call stack information in your logs. Without it, it may be difficult to hunt down some bugs.
It's worth noting that if you call PreserveStackTrace, then you can use throw or throw ex and you'll equally get the full stack trace information.

I found this useful trick on Chris Taylor's blog. If you want to use this with .NET 1, you should refer to Chris' post because it seems that the InternalPreserveStackTrace method didn't exist before .NET 2.0.

The complete source code is attached to this post.

Rethrowing exceptions and preserving the full call stack trace的更多相关文章

  1. The eventual following stack trace is caused by an error thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access, and has no functional impact.

    好久没有冒泡了,最近在新环境上搭建应用时,启动报错: INFO: Illegal access: this web application instance has been stopped alre ...

  2. java.lang.Exception: DEBUG -- CLOSE BY CLIENT STACK TRACE 的理解

    [2013-12-06 11:06:21,715] [C3P0PooledConnectionPoolManager[identityToken->2tl0n98y1iwg7cbdzzq7a|7 ...

  3. XDebug 自动开启PHP Stack Trace, 导致PHP Log 超1G

    昨天早上突然发现测试服务器空间满了,用du挨个文件夹查看,发现是php debug log占地极大,有的log直接有1G,打开后发现极其多的php stack trace. 立刻到主服务器查看,主服务 ...

  4. dump 分析模式之 INCORRECT STACK TRACE - djm2005dy的专栏 - 博客频道 - CSDN.NET

    Dump 分析模式之 INCORRECT STACK TRACE dump 分析模式之 INCORRECT STACK TRACE 翻译自 MDA-Anthology Page288  初学者常犯的错 ...

  5. Eclipse下Android开发错误之Unable to execute dex: java.nio.BufferOverflowException. Check the Eclipse log for stack trace

    升级了Android版本后,在运行应用时提示: [2013-11-27 10:37:35 - Dex Loader] Unable to execute dex: java.nio.BufferOve ...

  6. Android -- java.lang.NoClassDefFoundError: Class not found using the boot class loader; no stack trace available

    使用Bundle 的getParcelableArray 出现了以下错误: Class not found when unmarshallingjava.lang.ClassNotFoundExcep ...

  7. 让Xcode的 stack trace信息可读

    让Xcode的 stack trace信息可读 昨天在写 iOS 代码的时候,调试的时候模拟器崩溃了.异常停在了如下整个 main 函数的入口处: int main(int argc, char *a ...

  8. 项目跑起来之后,一会儿后台就会报错Illegal access: this web application instance has been stopped already. Could not load [com.mchange.v2.resourcepool.BasicResourcePool$1DestroyResourceTask]. The following stack trace

    一月 24, 2016 6:42:54 下午 org.apache.catalina.loader.WebappClassLoaderBase checkStateForResourceLoading ...

  9. Java 抓取 thread dump (Full Thread Stack Trace) 方法汇总

    顾名思义,表示一个时间点上,显示进程里面每一个线程的 stack trace,以及线程之间关联,比如等待 常用来定位一些 不响应,CPU 很高,内存使用很高问题 汇总表格如下 工具 操作系统 Java ...

随机推荐

  1. android-8~23 View.java - dispatchTouchEvent源码

    android-8 /** * Pass the touch screen motion event down to the target view, or this * view if it is ...

  2. git服务器新增仓库

    在已有的git库中搭建新的库,并将本地的git仓库,上传到服务器的git库中,从而开始一个新的项目. 首先是在本地操作: 在本地新建文件夹spider,进入到spider中:如下

  3. 摘记 史上最强大的40多个纯CSS绘制的图形(一)

    今天在国外的网站上看到了很多看似简单却又非常强大的纯CSS绘制的图形,里面有最简单的矩形.圆形和三角形,也有各种常见的多边形,甚至是阴阳太极和网站小图标,真的非常强大,分享给大家. Square(正方 ...

  4. selenium之操作ChromeDriver

    链接:http://www.testwo.com/blog/6931 1.下载ChromeDriver驱动包(下载地址: http://chromedriver.storage.googleapis. ...

  5. [源码]ObjectIOStream 对象流 ByteArrayIOStream 数组流 内存流 ZipOutputStream 压缩流

    1.对象流 import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File ...

  6. Unity3D优化总结

    1.在使用数组或ArrayList对象时应当注意 length=myArray.Length; for(int i=0;i<length;i++) { } 避免 for(int i=0;i< ...

  7. ZYNQ学习之——MIO

    1.GPIO基础知识 Zynq7000 系列芯片有 54 个 MIO(multiuse I/O) ,它们分配在 GPIO 的 Bank0 和Bank1 隶属于 PS 部分, 这些 IO 与 PS 直接 ...

  8. 【转】HTML5 jQuery图片上传前预览

    hTML5实现表单内的上传文件框,上传前预览图片,针刷新预览images,本例子主要是使用HTML5 的File API,建立一個可存取到该 file的url,一个空的img标签,ID为img0,把选 ...

  9. java中Color类的简单总结

    java中Color类的简单总结 1.颜色的常识 任何颜色都是由三原色组成(RGB),JAVA中支持224为彩色,即红绿蓝分量取值 介于0-255之间(8位表示) 2.Color类中的常量 publi ...

  10. WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default i

    jdbc连接数据库候,对数据进行访问,访问正常当出现如下警告: WARN: Establishing SSL connection without server's identity verifica ...