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. web api 开发记录

    1. 修改 api 返回时间格式 //配置返回的时间类型数据格式 GlobalConfiguration.Configuration.Formatters.JsonFormatter.Serializ ...

  2. Vs2015智能提示英文?

    Vs2015智能提示英文? 装了vs2015代码的智能提示全部变成英文了   找到这个目录 C:\Program Files (x86)\Reference Assemblies\Microsoft\ ...

  3. deep learning 练习 多变量线性回归

    多变量线性回归(Multivariate Linear Regression) 作业来自链接:http://openclassroom.stanford.edu/MainFolder/Document ...

  4. ASCIITable: 演示 Arduino 串口输出的进阶功能

    原文地址 - https://www.arduino.cc/en/Tutorial/ASCIITable ASCII字符表 本例展示了高级的串口打印功能,通过本功能可以在Arduino软件(IDE)的 ...

  5. 使用delphi+intraweb进行微信开发4—微信消息加解密

    示例代码已经放出!请移步使用delphi+intraweb进行微信开发1~4代码示例进行下载,虽为示例代码但是是从我项目中移出来的,封装很完备适于自行扩展和修改. 在上一讲当中我做了个简单的微信文本消 ...

  6. OpenCV的数据类型---Cv

    CvScalar就是一个包含四个元素的结构体变量. CvScalar定义可存放1—4个数值的数值,其结构如下. typedef struct CvScalar{    double val[4];}C ...

  7. [LeetCode OJ] Max Points on a Line

    Max Points on a Line Submission Details 27 / 27 test cases passed. Status: Accepted Runtime: 472 ms ...

  8. centos,apache运维经验

    1.防止php木马在apache下跨站 在/etc/php.ini 中设置open_basedir=.:/tmp/  , (还需要加载网站所在的目录) 2.shell下搜索木马 find ./ -ty ...

  9. autoit 使用excel自带函数操作excel

    Looking into the includes <Excel.au3> helped shed some light on things. To summarize what I've ...

  10. Semaphore用法

    HANDLE hSemaphore; cout<<1<<endl; hSemaphore = CreateSemaphore( NULL, 0, 10000, NULL);   ...