~每天一个历史遗留问题~熟悉异常的 C++++ coder,都知道
对于 throw ex; 与 throw; 是有区别的,主要是 CLR 确定异常抛出的起点是有区别的,
如果你不清楚请参考:
《.NET 框架程序设计》Jeffery Richter 李建忠译 chater 18.12 异常堆栈踪迹 P442 的说明或者见
throw;与throw ex;之间的区别
http://blog.csdn.net/Joy_Zhao/archive/2006/10/27/1352777.aspx
但是,下面的 Button1_Click 即使使用 throw; 也堆栈信息只能跟踪到 Line 14 ,始终无法跟踪到 Line 11,而 Button2_Click 直接到 Line 21// .aspx.cs
protected void Button1_Click(object sender, EventArgs e)
{
try {
object o = null;
int i = (int)o; // Line 11 // Error, System.NullReferenceException
}
catch {
throw; // Line 14
}
} protected void Button2_Click(object sender, EventArgs e)
{
object o = null;
int i = (int)o; // Line 21 // Error, System.NullReferenceException
}// .aspx
<asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Throw1" />
<asp:Button ID="Button2" runat="server" OnClick="Button2_Click" Text="Throw2" />
我做过很多测试了,对于用 try-catch-throw 捕获 CLR 运行时内部抛出的异常,即出现这种情况,始终无法跟踪到最原始的内部异常起点
何解 ?也许是我遗漏了某个知识点~谢谢!
对于 throw ex; 与 throw; 是有区别的,主要是 CLR 确定异常抛出的起点是有区别的,
如果你不清楚请参考:
《.NET 框架程序设计》Jeffery Richter 李建忠译 chater 18.12 异常堆栈踪迹 P442 的说明或者见
throw;与throw ex;之间的区别
http://blog.csdn.net/Joy_Zhao/archive/2006/10/27/1352777.aspx
但是,下面的 Button1_Click 即使使用 throw; 也堆栈信息只能跟踪到 Line 14 ,始终无法跟踪到 Line 11,而 Button2_Click 直接到 Line 21// .aspx.cs
protected void Button1_Click(object sender, EventArgs e)
{
try {
object o = null;
int i = (int)o; // Line 11 // Error, System.NullReferenceException
}
catch {
throw; // Line 14
}
} protected void Button2_Click(object sender, EventArgs e)
{
object o = null;
int i = (int)o; // Line 21 // Error, System.NullReferenceException
}// .aspx
<asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Throw1" />
<asp:Button ID="Button2" runat="server" OnClick="Button2_Click" Text="Throw2" />
我做过很多测试了,对于用 try-catch-throw 捕获 CLR 运行时内部抛出的异常,即出现这种情况,始终无法跟踪到最原始的内部异常起点
何解 ?也许是我遗漏了某个知识点~谢谢!
解决方案 »
- Excel导入DataGridView 字符串不能导入求解决办法
- 500g为单位…不足500g按照500g计算…例如400g=500g…501g=1000g…1001g=1500g…1600g=2000g...怎么写方法计算
- 怎么建立对话框啊,vs2005的工具箱中怎么没有啊
- C#缩略图问题
- 求两个表操作的SQL语句
- 请教一下MDI子窗体问题
- 怎样在winform中显示cad的图纸?
- 100分,求将一个asp功能用C#重写
- 求高手,这段c#链接access代码哪里错了
- 请各位看看到底是那里的问题。。。头都晕了。。
- 如何在program.cs中加入Timer事件
- *****谁能给一个多线程访问共享资源的问题,及解决方法******
单步可以调试到
int i = (int)o; // Line 11 // Error, System.NullReferenceException
protected void throwErr()
{
object o = null;
int i = (int)o; //Line4 //Error, System.NullReferenceException
} protected void Button1_Click(object sender, EventArgs e)
{
try
{
throwErr();
}
catch
{
throw;
}
} protected void Button2_Click(object sender, EventArgs e)
{
object o = null;
int i = (int)o; // Line 12 // Error, System.NullReferenceException
}
我想知道的是,底层方法如果加了 try-catch-throw,上层捕获,为何到不了 CLR 抛的异常起点,这点对于多层调用来说,调试很麻烦,
目前我采取的方式,只有手动包装一次异常// DAL
using(SqlConnection conn = new SqlConnection())
try {
// ...
// ... // here, some error occurs at line 911
// ...
}
catch(SqlException ex) {
throw new MyCustomApplictionException("some unknow error under db operation.", ex); // 这样顶层捕获,访问内部异常(这里即 ex),是可以追中到 line 911 的
}
也许我应该提供这样的测试实例: protected void Button1_Click(object sender, EventArgs e)
{
try {
ThrowException1();
}
catch(Exception ex) {
Response.Write(ex.StackTrace); // 这里只能到 line 40, 我希望的是 line 37
//Console.WriteLine(ex.StackTrace);
//throw;
}
} protected void Button2_Click(object sender, EventArgs e)
{ try {
ThrowException2();
}
catch(Exception ex) {
Response.Write(ex.StackTrace);
//Console.WriteLine(ex.StackTrace);
//throw;
}
} private void ThrowException1()
{
try {
object o = null;
int i = (int)o; // line 37
}
catch {
throw; // line 40
}
}
private void ThrowException2()
{
object o = null;
int i = (int)o;
}
Any way, thanks a lot.
我只知道
try{}catch(){} 是直接把异常抛出。
而
try{}catch(Exception ex){}是要先把异常实例化的,这个过程应该是拿到了很确凿的数据,所以这样是可以追踪到出错的位置的,ex.StackTrace 。
所以如果你想追踪异常的原始位置的话,应该写成后者,但这样效率会有所降低。。
try{}catch(){} 不会再抛出任何异常try{}catch(throw;){} , try{}catch(Exception)(throw;){} , try{}catch(Exception ex)(throw;){} 是等价的try{}catch(Exception ex)(throw;){} 与 try{}catch(Exception ex)(throw ex;){}
几乎是相同的,只是后者 CLR 会重新设定异常起点,前者 IL 指令是 rethrow 后者 IL 指令是 throw这里我要讨论的是,在我的测试场景中,throw; 与 throw ex; 竟然相同了,输出的堆栈信息是一样的。测试实例: protected void Button1_Click(object sender, EventArgs e)
{
try {
ThrowException1();
}
catch(Exception ex) {
Response.Write(ex.StackTrace); // 这里只能到 line 40, 我希望的是 line 37
//Console.WriteLine(ex.StackTrace);
//throw;
}
} protected void Button2_Click(object sender, EventArgs e)
{ try {
ThrowException2();
}
catch(Exception ex) {
Response.Write(ex.StackTrace);
//Console.WriteLine(ex.StackTrace);
//throw;
}
} private void ThrowException1()
{
try {
object o = null;
int i = (int)o; // line 37
}
catch {
throw; // line 40
}
}
private void ThrowException2()
{
object o = null;
int i = (int)o;
}
Any way, thanks a lot.
事实上,我是以前使用 Data Access Block SqlHelper 的使用,发现了的这个问题因为 SqlHelper 里面每个 ExecuteXXX 方法都包含了 try-catch-throw,我发现调用 ExecuteXXX 的方法,顶层捕获异常,堆栈信息只记录到 ExecuteXXX 方法的 throw 那一行,而无法到真正抛出异常的那一行,然后 ExecuteXXX 方法又是调用多个版本的重载方法,结果我就不知道到底是哪个方法,哪行代码错误了,我只有使用 try{ SqlHelper.ExecuteXXX } catch(SqlException ex) { throw new Exception("db operation failed.", ex); } 将内部异常包装一次可能,我还是无法描述清楚,回去把我的测试代码上传,供大家测试看看吧谢谢。
不过,请教下,
try{}catch(){throw;} 与try{}catch(Exception ex){throw ex;}
只是 你所说得 “前者 IL 指令是 rethrow 后者 IL 指令是 throw”的区别吗??还有,什么都不写 自动有系统踢出不可继续进行的error 和使用try{}catch(){throw;}
有什么区别呢??
关于 throw ex; 与 throw; 的区别,我顶楼已经提供了链接文章参考了
@RedGoldFish(红金鱼)
如果真是BUG,不知道 MS 何时修复对于异常处理情况十分的复杂,对于自己系统的底层框架,有时候我们只是希望捕获异常,然后执行一些资源释放的操作,重新丢出异常,并希望保持堆栈信息,一遍尽快查找错误,重新包装一次异常,给我们程序员带来了而外工作,有时候,我就真的不希望此异常做说明解释或者说明,直接继续向上抛,留给上层应用程序处理
using System.Collections.Generic;
using System.Text;namespace TryCatchThrowTestConsole
{
class Program
{
static void Main(string[] args)
{
Tester tester = new Tester(); System.Text.StringBuilder sb = new System.Text.StringBuilder(); /*
* 说明
* 1. 以下 ThrowEx_ 两两成对比较
* 2. ThrowEx7 和 ThrowEx8 演示已知的 throw; 与 throw ex; 的不同,即后者 CLR 重新设置异常的起点
* 位于异常捕获点之上中的调用堆栈信息不会包含在 Exception 的 StackTrace 属性中
* 3. ThrowEx1 和 ThrowEx2 演示本讨论的直接目标:为什么 ThrowEx2 中使用 throw; 堆栈信息也无法包括到 F2_1 这一行,而是直接到 F2_2
* 4. ThrowEx3 和 ThrowEx4 情形同 ThrowEx1 和 ThrowEx2
* 5. ThrowEx5 与 ThrowEx6 效果相同。
* 6. try{//...}catch{throw;}, try{//...}catch(Exception){throw;}, try{//...}catch(Exception ex){throw;} 三者是等价的
*/ try {
tester.ThrowEx1();
}
catch (Exception ex) {
sb.AppendLine("1");
sb.AppendLine(ex.StackTrace); // 堆栈信息如期到 F1_1
sb.AppendLine();
} try {
tester.ThrowEx2();
}
catch (Exception ex) {
// 堆栈信息只能到 F2_2,我的疑问是为什么不能到 F2_1
// ThrowEx2() 与 ThrowEx1() 唯一区别就是 ThrowEx1() 内部还有一个 try-catch-throw
sb.AppendLine("2");
sb.AppendLine(ex.StackTrace);
sb.AppendLine(); //sb.AppendLine("-----------");
//sb.AppendLine(System.Environment.StackTrace);
//sb.AppendLine("-----------"); System.Diagnostics.StackTrace st = new System.Diagnostics.StackTrace(ex);
sb.AppendLine("-----------");
sb.AppendLine(st.ToString());
sb.AppendLine("-----------");
} try {
tester.ThrowEx3();
}
catch (Exception ex) {
sb.AppendLine("3");
sb.AppendLine(ex.StackTrace);
sb.AppendLine();
} try {
tester.ThrowEx4();
}
catch (Exception ex) {
sb.AppendLine("4");
sb.AppendLine(ex.StackTrace);
sb.AppendLine();
} try {
tester.ThrowEx5();
}
catch (Exception ex) {
sb.AppendLine("5");
sb.AppendLine(ex.StackTrace);
sb.AppendLine();
} try {
tester.ThrowEx6();
}
catch (Exception ex) {
sb.AppendLine("6");
sb.AppendLine(ex.StackTrace);
sb.AppendLine();
} try {
tester.ThrowEx7();
}
catch (Exception ex) {
sb.AppendLine("7");
sb.AppendLine(ex.StackTrace);
sb.AppendLine();
} try {
tester.ThrowEx8();
}
catch (Exception ex) {
sb.AppendLine("8");
sb.AppendLine(ex.StackTrace);
sb.AppendLine();
} string result = sb.ToString();
System.IO.File.WriteAllText("result.txt", result); // 输出到文件
Console.WriteLine(result); // 输出到控制台 Console.Write("press any key to exit...");
Console.ReadKey();
} public class Tester
{
public void ThrowEx1()
{
int i = 0, j = 0;
int k = i / j; // F1_1
} public void ThrowEx2()
{
try {
int i = 0, j = 0;
int k = i / j; // F2_1
}
catch { // 这里 try{}catch(DivideByZeroException){throw;}, try{}catch(DivideByZeroException ex){throw;} 等价
throw; // F2_2
}
} public void ThrowEx3()
{
throw new DivideByZeroException(); // F3_1
} public void ThrowEx4()
{
try {
throw new DivideByZeroException(); // F4_1
}
catch {
throw; // F4_2
}
} public void ThrowEx5()
{
ThrowEx1(); // F5_1
} public void ThrowEx6()
{
try {
ThrowEx1(); // F6_1
}
catch {
throw; // F6_2
}
} public void ThrowEx7()
{
try {
ThrowEx1(); // F7_1
}
catch (DivideByZeroException) { // 这里与 try{}catch{throw;}, try{}catch((DivideByZeroException ex){throw;} 等价
throw; // F7_2
}
} public void ThrowEx8()
{
try {
ThrowEx1(); // F8_1
}
catch (DivideByZeroException ex) {
throw ex; // F8_2
}
}
}
}
}