Try-Catch无法正确定位异常位置,我推荐2个有效技巧
宇宙第一开发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个有效技巧的更多相关文章
- WinDBG快速定位异常位置
在WinDBG中通过搜索内存中保存的CONTEXT结构来定位发生的异常信息,再通过WinDBG命令.cxr显示对应的调用堆栈信息. .foreach ( place { s-[1]d 0 L?FF ...
- springmvc请求参数异常统一处理,结合钉钉报告信息定位bug位置
参考之前一篇博客:springmvc请求参数异常统一处理 1.ExceptionHandlerController package com.oy.controller; import java.tex ...
- JUnit 4 如何正确测试异常
本篇讲述如何在 JUnit 4 下正确测试异常,我会从 try..catch 的方式谈起,然后说到 @Test(expected=Exception.class), 最后论及 @Rules publi ...
- .net程序调试一:快速定位异常
作为一个程序员,解BUG是我们工作中常做的工作,甚至可以说解决问题能力是一个人工作能力的重要体现.因为这体现了一个程序员的技术水平.技术深度.经验等等. 那么在我们解决BUG的过程中,定位问题是非常重 ...
- .NET程序调试技巧(一):快速定位异常的一些方法
作为一个程序员,解BUG是我们工作中常做的工作,甚至可以说解决问题能力是一个人工作能力的重要体现.因为这体现了一个程序员的技术水平.技术深度.经验等等. 那么在我们解决BUG的过程中,定位问题是非常重 ...
- TextArea中定位光标位置
原文:TextArea中定位光标位置 在项目中,遇到一个场景:希望能在TextArea中输入某条记录中的明细(明细较简单,没有附属信息,只用记录顺序和值即可,譬如用"+"号来作为明 ...
- oops_根据epc定位linux_kernel_panic位置
韩大卫@吉林师范大学 2014.12.10 转载请表明出处 ***************************************************** 关于内核报错 “Unable t ...
- C#Exception 追踪异常位置
1:在编写软件时,保护关键位置的代码正常运行,要对这位置进行异常处理try catch private void StartTCPServer() { try { ........//我们要确保知道这 ...
- hp小机定位网卡位置
rad已经被olrad取代 HPUX下定位网卡位置 一台HP小型机,可能配了多块网卡,在系统中以la ...
随机推荐
- python操作mongo实例
# coding:utf-8 """ mongo操作工具 """ from pymongo import MongoClient MONGO ...
- Python与C语言基础对比(Python快速入门)
代码较长,建议使用电脑阅读本文. 10分钟入门Python 本文中使用的是Python3 如果你曾经学过C语言,阅读此文,相信你能迅速发现这两种语言的异同,达到快速入门的目的.下面将开始介绍它们的异同 ...
- Java 浮点数精度控制
1.String.format(String format,Object… args) Java中用String.format()来控制输出精度, format参数用来设置精度格式, args参数代 ...
- 在网页中插入背景音乐代码(html)
有两种 分别用<bgsound>和<embed></embed>标签,当用<embed>插入背景音乐时可以设置宽度和高度为0,隐藏播放器. 二者的参数如 ...
- 每天进步一点点------创建Microblaze软核(一)
在使用FPGA时,有时会用到它做为主控芯片.对于习惯于单片机及C语言开发的人,使用FPGA做主控芯片,首先还是想到它的嵌入式软核功能.如果能够基于Microblze软核进行C语言程序的开发,相对于使用 ...
- docker删除镜像时报错解决办法
报错信息 [root@kvm ~]# docker rmi 4950a54ede5a Error response from daemon: conflict: unable to delete 49 ...
- Java“被迫”退出争霸,Python继续霸占首位!老牌程序员:我不服
2019年转眼已经接近尾声,如果盘点下2019年最火的语言,除了Python还能有谁?你心中的王者语言又是谁? 这一年Python风光无限 这一年JAVA走向右边 这一年,我们都很感慨,你呢? 关于P ...
- python 变量的赋值【内存地址】
注意: python所有的数据都是对象,变量只是指向一个对象的地址,一旦将变量的值或者类型改变,变量指向的地址就有可能发生变化 这个特性在使用默认参数的时候一定要注意
- Eugeny and Array(思维)
Eugeny has array a = a1, a2, ..., an, consisting of n integers. Each integer ai equals to -1, or to ...
- ASP.NET/C# Razor视图引擎深入浅出
在ASPX中我们使用 <% %>在里面编写C#代码在Razor中我们将会使用@{}编写C#代码1.基础——@+属性显示计算1+2的值:<span>1+2=@(1+2)</ ...