宇宙第一开发IDE Visual Studio的调试功能非常强大,平常工作debug帮助我们解决不少问题。今天分享两个异常捕获的技巧,希望能够帮助解决一些问题。

以下两种情况,我相信大家都会遇到过。

  • 1.没有使用Try-Catch语句,当异常发生的时候,能够自动跳转到异常发生的地方,在使用Try-Catch捕获异常的时候,直接跳转到Catch语句的位置,并不会自动定位到异常代码的位置。
  • 2.使用Try-Catch的时候,多层方法调用时,并不能直接查看到异常代码的位置。

技巧1:自动定位到异常代码位置

针对问题1,我们最想要的结果是,哪里有代码出现错误了,就直接定位到哪儿,异常出在哪行代码上,我一眼就能看得出,这样就能更快地处理问题了。

对于问题1,所出现的这种情况,简单复现一下一个空引用的异常

namespace ExceptionSample
{
class Program
{
static void Main(string[] args)
{
try
{
Random random = null;
Console.WriteLine(random.Next());
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
Console.ReadLine();
}
}
}

上面的异常代码NullReferrenceException,Debug模式下,会跳转到catch语句这里。你可能觉得这挺简单的......可实际实际工作中,你的一个方法中仅仅只这一个对象吗?



在实际工作中可能不止random一个对象,代码复杂,对象够多,几十个也有,我们就很难定位到异常出错的代码了。StackTrace可以定位到那个函数调用错了,并不能定位到哪一行代码出错了。

为了解决这个行为可以通过在Visual Studio中菜单栏中的调试》窗口》异常设置中去配置。如下图所示:



勾选上Common Language Runtime Exceptions下列的异常单选框。有点多,以前的设置有些变化。

现在我们再看之前的代码,使用Try-Catch语句捕获异常的时候,就会直接定位到异常代码的位置了,如下图示:

       static void Main(string[] args)
{
try
{
Random random = null;
Random random1 = new Random();
Random random2 = new Random();
Random random3 = new Random();
Console.WriteLine(random1.Next());
Console.WriteLine(random2.Next());
Console.WriteLine(random3.Next());
Console.WriteLine(random.Next());
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
Console.ReadLine();
}

技巧2:正常的throw 姿势

还是之前的一个方法,我已经将异常设置回复默认了。

        static void Main(string[] args)
{
try
{
Random random = null;
Console.WriteLine(random.Next());
}
catch (Exception ex)
{
System.Diagnostics.Debug.Write(ex);
throw ex;
}
}

我们再输出中可以看到(ps:项目名称用的之前的,不介意哈)



错误的代码在16行。可实际工作中的情况并不是这样简单,基本上是A方法调用B方法,B方法调用C方法,代码如下所示:

在Main方法中调用ThrowNullReferrence(),方法ThrowNullReferrence中调用SetNullReferrence()。代码变复杂后,一层嵌套一层。这个时候能正确显示出代码异常的位置吗?

        static void Main(string[] args)
{
try
{
ThrowNullReferrence();
}
catch (Exception ex)
{
System.Diagnostics.Debug.Write(ex);
throw ex;
}
}
public static void ThrowNullReferrence()
{
try
{
SetNullReferrence();
}
catch (Exception ex)
{
System.Diagnostics.Debug.Write(ex);
throw ex;
}
}
public static void SetNullReferrence()
{
try {
Random random = null;
Console.WriteLine(random.Next());
}
catch(Exception ex)
{
System.Diagnostics.Debug.Write(ex);
throw ex;
}
}

我们可以通过下图看到:



System.NullReferenceException: 未将对象引用设置到对象的实例。

在 ExceptionSample.Program.SetNullReferrence() 位置 D:\Learn\延迟加载\LinqLayzLoad\LinqLayzLoad\Program.cs:行号 39System.NullReferenceException: 未将对象引用设置到对象的实例。

在 ExceptionSample.Program.SetNullReferrence() 位置 D:\Learn\延迟加载\LinqLayzLoad\LinqLayzLoad\Program.cs:行号 44

在 ExceptionSample.Program.ThrowNullReferrence() 位置 D:\Learn\延迟加载\LinqLayzLoad\LinqLayzLoad\Program.cs:行号 27System.NullReferenceException: 未将对象引用设置到对象的实例。

在 ExceptionSample.Program.ThrowNullReferrence() 位置 D:\Learn\延迟加载\LinqLayzLoad\LinqLayzLoad\Program.cs:行号 32

在 ExceptionSample.Program.Main(String[] args) 位置 D:\Learn\延迟加载\LinqLayzLoad\LinqLayzLoad\Program.cs:行号 15

错误代码的位置在39行,以上出现异常的地方都是throw的位置。

原因呢?

catch捕获完后,如果要向上抛出,应该重新实例化一个新的异常对象,再向上抛出,这个最外层方法catch到的才是完整的异常,当然也包括完整的堆栈信息,这样才能定位到异常代码的位置。

要使用 throw new Exception

改造后的例子如图,精准定位到

39行的空引用异常

Console.WriteLine(random.Next());

结语

分享之前看到的一个老程序员的经验之谈:“多coding,少debug”

Try-Catch无法正确定位异常位置,我推荐2个有效技巧的更多相关文章

  1. WinDBG快速定位异常位置

    在WinDBG中通过搜索内存中保存的CONTEXT结构来定位发生的异常信息,再通过WinDBG命令.cxr显示对应的调用堆栈信息.   .foreach ( place { s-[1]d 0 L?FF ...

  2. springmvc请求参数异常统一处理,结合钉钉报告信息定位bug位置

    参考之前一篇博客:springmvc请求参数异常统一处理 1.ExceptionHandlerController package com.oy.controller; import java.tex ...

  3. JUnit 4 如何正确测试异常

    本篇讲述如何在 JUnit 4 下正确测试异常,我会从 try..catch 的方式谈起,然后说到 @Test(expected=Exception.class), 最后论及 @Rules publi ...

  4. .net程序调试一:快速定位异常

    作为一个程序员,解BUG是我们工作中常做的工作,甚至可以说解决问题能力是一个人工作能力的重要体现.因为这体现了一个程序员的技术水平.技术深度.经验等等. 那么在我们解决BUG的过程中,定位问题是非常重 ...

  5. .NET程序调试技巧(一):快速定位异常的一些方法

    作为一个程序员,解BUG是我们工作中常做的工作,甚至可以说解决问题能力是一个人工作能力的重要体现.因为这体现了一个程序员的技术水平.技术深度.经验等等. 那么在我们解决BUG的过程中,定位问题是非常重 ...

  6. TextArea中定位光标位置

    原文:TextArea中定位光标位置 在项目中,遇到一个场景:希望能在TextArea中输入某条记录中的明细(明细较简单,没有附属信息,只用记录顺序和值即可,譬如用"+"号来作为明 ...

  7. oops_根据epc定位linux_kernel_panic位置

    韩大卫@吉林师范大学 2014.12.10 转载请表明出处 ***************************************************** 关于内核报错 “Unable t ...

  8. C#Exception 追踪异常位置

    1:在编写软件时,保护关键位置的代码正常运行,要对这位置进行异常处理try catch private void StartTCPServer() { try { ........//我们要确保知道这 ...

  9. hp小机定位网卡位置

    rad已经被olrad取代 HPUX下定位网卡位置                                                   一台HP小型机,可能配了多块网卡,在系统中以la ...

随机推荐

  1. AcWing 827. 双链表

    https://www.acwing.com/problem/content/829/ #include <iostream> using namespace std; ; int m; ...

  2. Docker常用命令及脚本

    1.常用命令 docker          search centos                                #搜索镜像              pull centos   ...

  3. 无聊学习一下MVP这个概念

    记录一下学习MVP,好处是便于替换前台页面(winfrom替换成asp.net),不改变页面逻辑层及其以后的层 M:业务逻辑 V:页面 P:页面逻辑 ,充当 页面和业务逻辑的中间层 规则:V和M不能直 ...

  4. 生产环境设置mysql主从复制

    Slave服务器的版本要等于或者高于master服务器 现在的实例是在mysql 5.7上的主从配置 a) master服务器的my.cnf配置,server_id 推荐用IP的后两位数字 [mysq ...

  5. EAC3 Adaptive Hybrid Transform (AHT)

    adaptive hybrid transform 由两个linear transforms级联组成. 第一个transform为MDCT,MDCT使用KBD window产生256个transfor ...

  6. 10-Java-JSTL标签库的使用

    使用JSTL标签库使用 第一步:引入相关jar包到WEB-INF/lib/,JSTL标签库(standard.jar,jstl.jar) 第二步:在JSP文件中通过 taglib指令引入标签库,例如: ...

  7. python接口自动化测试 - requests库的post请求进行文件上传

    前言 如果需要发送文件到服务器,比如上传图片.视频等,就需要发送二进制数据. 一般上传文件使用的都是 Content-Type: multipart/form-data; 数据类型,可以发送文件,也可 ...

  8. JS字符串的不可变性

    js中的字符串特性->不可变性,字符串的值是不可变的 1.改变字符串中的字符 var str = "hello"; str[1] = "W"; conso ...

  9. VSCode配置FTP

    首先在VScode中下载安装插件SFTP Windwos下摁Ctrl+Shift+P,输入SFTP: config命令并运行,进入sftp.json配置项如下: { "name": ...

  10. ubuntu16.04spyder闪退

    解决办法我试了好用 sudo pip install --upgrade html5lib==.0b8 完事.