博客园  :: 首页  :: 新随笔  :: 订阅 订阅  :: 管理

C# 捕获异常详情

Posted on 2011-02-22 18:23  PHP-张工  阅读(58700)  评论(8编辑  收藏  举报

如何获取异常的详细信息。

捕获异常

//触发异常
private void test()
{
	int i = 0;
	i = 12 / i;
}

//直接捕获异常
private void button1_Click(object sender, EventArgs e)
{
	try
	{
		test();
	}
	catch (Exception ex)
	{
		this.textBox1.Text = ex.ToString();
	}
}

错误信息:

System.DivideByZeroException: 试图除以零。
   在 ExceptionTest.Form1.test() 位置 C:\Documents and Settings\Administrator\桌面\ExceptionTest\Form1.cs:行号 25
   在 ExceptionTest.Form1.button1_Click(Object sender, EventArgs e) 位置 C:\Documents and Settings\Administrator\桌面\ExceptionTest\Form1.cs:行号 33

通过错误信息可以发现提示信息显示错误行是 i = 12 / i; 这行。

捕获异常问题

而实际上我们有可能捕获异常后处理完成后会在将异常抛给调用程序

//间接捕获异常
private void button2_Click(object sender, EventArgs e)
{
	try
	{
		test1();
	}
	catch (Exception ex)
	{
		this.textBox1.Text = ex.ToString();
	}
}

private void test1()
{
	try
	{
		test();
	}
	catch (Exception ex)
	{
		//错误处理...

		throw ex;
	}
}

错误信息:

System.DivideByZeroException: 试图除以零。
   在 ExceptionTest.Form1.test1() 位置 C:\Documents and Settings\Administrator\桌面\ExceptionTest\Form1.cs:行号 63
   在 ExceptionTest.Form1.button2_Click(Object sender, EventArgs e) 位置 C:\Documents and Settings\Administrator\桌面\ExceptionTest\Form1.cs:行号 46

通过错误信息可以发现提示信息显示错误行是 throw ex;这行。
根据如上的错误提示是很难发现根本错误原因的。为什么没有提示i = 12 / i;行错误呢?
是因为代码已经使用try catch将除零错误捕获,捕获后又抛出了此异常!又被外层函数捕捉后,错误中就只留下了throw时的错误行信息。

那如何才可以获取具体的异常呢?

//解决方法
private void button3_Click(object sender, EventArgs e)
{
	try
	{
		test2();
	}
	catch (Exception ex)
	{
		this.textBox1.Text = ex.ToString();
	}
}

private void test2()
{
	try
	{
		test();
	}
	catch (Exception ex)
	{
		//自定义异常
		throw new Exception("出错啦!", ex);
	}
}

错误信息:

System.Exception: 出错啦! ---> System.DivideByZeroException: 试图除以零。
   在 ExceptionTest.Form1.test() 位置 C:\Documents and Settings\Administrator\桌面\ExceptionTest\Form1.cs:行号 25
   在 ExceptionTest.Form1.test2() 位置 C:\Documents and Settings\Administrator\桌面\ExceptionTest\Form1.cs:行号 84
   --- 内部异常堆栈跟踪的结尾 ---
   在 ExceptionTest.Form1.test2() 位置 C:\Documents and Settings\Administrator\桌面\ExceptionTest\Form1.cs:行号 89
   在 ExceptionTest.Form1.button3_Click(Object sender, EventArgs e) 位置 C:\Documents and Settings\Administrator\桌面\ExceptionTest\Form1.cs:行号 72

因为throw new Exception("出错啦!", ex); 重新创建了新的自定义异常,并且将原始异常设置为innerException;所以异常信息中包含了多个层次的异常信息。

关于异常在DEBUG RELEASE版的差异。

以上异常信息是在DEBUG模式下。
DEBUG RELEASE在VS调试状态下获取结果相同。
当在RELEASE独立运行时
RELEASE模式下 无ExceptionTest.pdb
System.Exception: 出错啦!
---> System.DivideByZeroException: 试图除以零。
   在 ExceptionTest.Form1.test2() 
  --- 内部异常堆栈跟踪的结尾 ---
   在 ExceptionTest.Form1.test2()
   在 ExceptionTest.Form1.button3_Click(Object sender, EventArgs e)
RELEASE模式下
System.Exception: 出错啦!
---> System.DivideByZeroException: 试图除以零。
   在 ExceptionTest.Form1.test2() 位置 C:\Documents and Settings\Administrator\桌面\ErrorLog\ExceptionTest\Form1.cs:行号 84
   --- 内部异常堆栈跟踪的结尾 ---
   在 ExceptionTest.Form1.test2() 位置 C:\Documents and Settings\Administrator\桌面\ErrorLog\ExceptionTest\Form1.cs:行号 89
   在 ExceptionTest.Form1.button3_Click(Object sender, EventArgs e) 位置 C:\Documents and Settings\Administrator\桌面\ErrorLog\ExceptionTest\Form1.cs:行号 72 

总结

注意在捕获并抛出异常时应使用 throw new Exception("出错啦!", ex); 方式,则可获得异常的具体位置。

当在VS调试或者DEBUG模式下运行程序成都可获得异常发生的具体位置。

但当在独立运行的RELEASE模式下时,异常只会记录最初的调用位置。

当执行目录不包含 *.pdb 文件时,异常信息中不会包含代码及行号信息。

测试代码下载

下载:https://files.cnblogs.com/zjfree/ErrorLog.rar

环境:WIN2003 + VS2005 + C#

补充

经园友 孤剑 指正!catch 了异常后,如果不处理,直接写 throw 即可,不用 throw ex; 示例如下:

try
{
    test();
}
catch
{
    //异常处理
    throw;
}

而对于无须异常处理的情况,写法如下:

try
{
    test();
}
finally
{
    //释放资源
}

经测试完全正确!以前真不知道这样也行。汗!非常感谢提醒!