宇宙第一开发 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"
来源: https://www.cnblogs.com/zhangmumu/p/12007159.html