System.Excelption 类型提供的制度 StackTrace 属性。
catch 块可读取该属性来获取一个堆栈跟踪,它描述了异常发生前调用了哪些方法。检查异常原因并改正代码时,这些信息很有用。访问该属性实际会调用 CLR 中的代码;该属性不是简单的放回一个字符串。构造 Exception 派生类型的新对象时,StackTrace 属性被初始化为 null。如果此时读取该属性,得到的不是堆栈跟踪,而是一个 null。
一个异常抛出时,CLR 在内部记录 throw 指令的位置(抛出位置)。一个 catch 块捕捉到该异常时,CLR 记录捕捉位置。在 catch 块内访问被抛出的异常对象的 StackTrace 属性,负责实现该属性的代码会调用 CLR 内部的代码,后者创建一个字符串来指出从异常抛出位置到异常捕捉位置的所有方法。
(抛出异常时,CLR 会重置异常起点;也就是说,CLR 只记录最新异常对象的抛出位置。)
以下代码抛出它捕捉到的相同的异常对象,导致 CLR 重置该异常的起点:
private void SomeMethod() { try{...} catch(Exception e) { throw e;// CLR 认为这是异常的起点,FxCop报错 } }
但如果仅仅适用 throw 关键字本身(删除后面的 e)来重新抛出异常对象,CLR 就不会重置堆栈的起点。
实际上,两端代码唯一的区别就是 CLR 对于异常起始抛出位置的认知。遗憾的是,不管抛出还是重新抛出,Windows 都会重置栈的起点。详见(CLR Via C# 4.0 P408)。