在日常项目开发中,异常抛出和捕获是再平常不过的事情。通过try-catch我们可以方便的捕获异常,同时通过查看异常堆栈我们能发现抛出异常代码的位置。

例如下面这段代码:

 using System;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; namespace ExamplesProject
{
class Program
{
static int m = ;
static void Main(string[] args)
{
try
{
int a = , b = ;
Console.WriteLine(a / b);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
} Console.ReadLine();
}
}
}

这段代码非常简单,运行后他抛出了如下异常:

System.DivideByZeroException: Attempted to divide by zero.
at ExamplesProject.Program.Main(String[] args) in D:\Projects\ExamplesProject\ExamplesProject\Program.cs:line

没有问题,堆栈信息明确指出了抛出异常的位置,也正是除零异常发生的位置。

假如因为种种原因,需要把main方法的代码逻辑抽取到另外的方法里,像下面这样:

 using System;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; namespace ExamplesProject
{
class Program
{
static int m = ;
static void Main(string[] args)
{
try
{
Divide();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
} Console.ReadLine();
} public static void Divide()
{
try
{
int a = , b = ;
Console.WriteLine(a / b);
}
catch (Exception ex)
{
throw ex;
}
}
}
}

这段代码乍一看,好像也没有什么问题,divide的方法自己捕获并重新抛出了异常。

再来看一下异常信息:

System.DivideByZeroException: Attempted to divide by zero.
at ExamplesProject.Program.Divide() in D:\Projects\ExamplesProject\ExamplesProject\Program.cs:line
at ExamplesProject.Program.Main(String[] args) in D:\Projects\ExamplesProject\ExamplesProject\Program.cs:line

异常堆栈显示,抛出异常的方法是Divide(),异常代码位置是34行。可这里并不是异常真正的发生位置,真正的异常位置是第30行。

发生了什么??为什么不是第30行。

再来看一个例子。

假如业务变复杂了,代码又嵌套了一层。调用关系变复杂了,main()->divide()->divide1()。

 using System;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; namespace ExamplesProject
{
class Program
{
static int m = ;
static void Main(string[] args)
{
try
{
Divide();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
} Console.ReadLine();
} public static void Divide()
{
try
{
Divide1();
}
catch (Exception ex)
{
throw ex;
}
} public static void Divide1()
{
try
{
int a = , b = ;
Console.WriteLine(a / b);
}
catch (Exception ex)
{
throw ex;
}
}
}
}

运行代码,抛出如下异常:

System.DivideByZeroException: Attempted to divide by zero.
at ExamplesProject.Program.Divide() in D:\Projects\ExamplesProject\ExamplesProject\Program.cs:line
at ExamplesProject.Program.Main(String[] args) in D:\Projects\ExamplesProject\ExamplesProject\Program.cs:line

为什么异常位置是33行,而不是42行呢。代码嵌套的越深,错误隐藏的越深。如果是在大型系统中,将很难发现错误的真正位置。

作者就犯过这样的错误啊。问题到底在哪里呢?

问题的根源是,以上代码抛出的异常并没有体现层次关系,或者说异常的嵌套关系。理论上讲,divide1()方法中catch捕获到的异常为最内层异常,catch捕获后处理完,如果要向上层抛出,应该重新实例化一个新的异常对象,并将当前异常作为其innerException, 再向上抛出。以此类推,divide()方法捕获处理后如果要抛出异常也应该这样做。这样最外层的main方法catch到的异常才是完整的异常,自然包含完整的堆栈信息,错误定位就是精准的。

改造后的例子:

 using System;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; namespace ExamplesProject
{
class Program
{
static int m = ;
static void Main(string[] args)
{
try
{
Divide();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
} Console.ReadLine();
} public static void Divide()
{
try
{
Divide1();
}
catch (Exception ex)
{
throw new Exception(ex.Message, ex);
}
} public static void Divide1()
{
try
{
int a = , b = ;
Console.WriteLine(a / b);
}
catch (Exception ex)
{
throw new Exception(ex.Message, ex);
}
}
}
}

运行后,抛出如下异常:

System.Exception: Attempted to divide by zero. ---> System.Exception: Attempted to divide by zero. ---> System.DivideByZeroException: Attempted to divide by zero.
at ExamplesProject.Program.Divide1() in D:\Projects\ExamplesProject\ExamplesProject\Program.cs:line
--- End of inner exception stack trace ---
at ExamplesProject.Program.Divide1() in D:\Projects\ExamplesProject\ExamplesProject\Program.cs:line
at ExamplesProject.Program.Divide() in D:\Projects\ExamplesProject\ExamplesProject\Program.cs:line
--- End of inner exception stack trace ---
at ExamplesProject.Program.Divide() in D:\Projects\ExamplesProject\ExamplesProject\Program.cs:line
at ExamplesProject.Program.Main(String[] args) in D:\Projects\ExamplesProject\ExamplesProject\Program.cs:line

这一次,异常堆栈精准的定位了异常代码行第42行。

总结,以上例子非常简单,可是在实际开发中,我们总是会不经意忽略一些细节,最终导致上了生产后异常格外的难以追踪。

c# 异常精准定位的更多相关文章

  1. postgresql异常快速定位

    今天下午在使用.NET链接postgresql的时候报了“3D000”的错误,经过测试得知原来是web.config中的数据库配置问题. 在这里有个小情况需要注意,postgresql是不允许创建相同 ...

  2. 如何实现室内Wi-Fi无线终端的精准定位

    如何实现室内Wi-Fi无线终端的精准定位 如何实现室内Wi-Fi无线终端的精准定位 随着商圈020的兴起,室内定位技术的也如百花争艳般不断涌现.但随着室内Wi-Fi网的架设普及,基于Wi-Fi定位技术 ...

  3. vue开发东京买菜,全栈项目,前端django,带手机GPS精准定位,带发票系统,带快递系统,带微信/支付宝/花呗/银行卡支付/带手机号一键登陆,等等

    因为博客园不能发视频,所以,完整的视频,开发文档,源码,请向博主索取 完整视频+开发文档+源码,duanshuiLu.com下载 vue+django手机购物商城APP,带支付,带GPS精准定位用户, ...

  4. django开发东京买菜,全栈项目,前端vue,带手机GPS精准定位,带发票系统,带快递系统,带微信/支付宝/花呗/银行卡支付/带手机号一键登陆,等等

    因为博客园不能发视频,所以,完整的视频,开发文档,源码,请向博主索取 完整视频+开发文档+源码,duanshuiLu.com下载 vue+django手机购物商城APP,带支付,带GPS精准定位用户, ...

  5. 利用 Traceview 精准定位启动时间测试的异常方法 (工具开源)

    机智的防爬虫标识原创博客地址:http://www.cnblogs.com/alexkn/p/7095855.html博客求关注: http://www.cnblogs.com/alexkn 1.启动 ...

  6. Ceph RGW服务 使用s3 java sdk 分片文件上传API 报‘SignatureDoesNotMatch’ 异常的定位及规避方案

    import java.io.File;   import com.amazonaws.AmazonClientException; import com.amazonaws.auth.profile ...

  7. 大数据量冲击下Windows网卡异常分析定位

    背景 mqtt的服务端ActiveMQ在windows上,多台PC机客户端不停地向MQ发送消息. 现象 观察MQ自己的日志data/activemq.log里显示,TCP链接皆异常断开.此时尝试从服务 ...

  8. web异常流量定位:iftop+tcpdump+wireshark

    一个简单的运维小经验. 场景:web服务器出现异常流量,web集群内部交互出现大流量,需要定位具体的http请求,以便解决问题. 目的:找出产生大流量的具体http请求. 工具:        ift ...

  9. 记录一次cefsharp1输入法在win7下异常解决定位

    最近几天都被基于cefSharp封装的浏览器控件搞疯了!对于cefSharp基本满足当前所做项目的需求,但是有一个问题一直困扰我,那就是系统中偶尔会出现输入法不能转换到中文.而且这个问题似乎没有什么规 ...

随机推荐

  1. Common Lisp学习资源整理

    Lisp Hackers: Interviews with 100x More Productive Programmers Posted on June 26th, 2013 Lisp Hacker ...

  2. 初步了解JVM第二篇

    在一篇<初步了解JVM第一篇>中,我们已经了解了: 类加载器:负责加载*.class文件,将字节码内容加载到内存中.其中类加载器的类型有如下: 启动类加载器(Bootstrap) 扩展类加 ...

  3. JavaScript实现动态轮播图效果

    功能描述: 1.鼠标经过 左右侧箭头显示,鼠标离开 箭头隐藏 2.动态添加底部小圆圈并绑定单击事件,并且让小圆圈的点击事件和左右箭头点击事件同步 3.拷贝第一张图片添加到ul最后可以实现动态添加图片 ...

  4. 开源资产管理系统Snipe-IT

    CentOS7安装IT资产管理系统Snipe-IT介绍资产管理工具Github:https://github.com/snipe/snipe-it官网:https://snipeitapp.com/D ...

  5. Android判断com.android.camera.action.CROP是否存在

    版权声明:本文为xing_star原创文章,转载请注明出处! 本文同步自http://javaexception.com/archives/225 最近线上报错,有个用户连续crash了10次左右,查 ...

  6. Android Healthd电池服务分析

    healthd healthd是安卓4.4之后提出来的,监听来自kernel的电池事件,并向上传递电池数据给framework层的BatteryService.BatteryService计算电池电量 ...

  7. Path Manipulation 路径操作

  8. Prometheus学习系列(五)之Prometheus 规则(rule)、模板配置说明

    前言 本文来自Prometheus官网手册1.2.3.4和 Prometheus简介1.2.3.4 记录规则 一.配置规则 Prometheus支持两种类型的规则,这些规则可以定期配置,然后定期评估: ...

  9. 基于Git的数据库sql文件的管理——完美解决团队sql操作协同问题

    目录 基于Git的数据库sql文件的管理--完美解决团队sql操作协同问题 1.产生背景 2.之前没用Git管理数据库出现的问题 2.1 用同一个库调试带来的问题 3.解决方案 3.1 Sql文件的创 ...

  10. Redis面试篇 -- 如何保证缓存与数据库的双写一致性?

    如果不是严格要求“缓存和数据库”必须保证一致性的话,最好不要做这个方案:即 读请求和写请求串行化,串到一个内存队列里面去.串行化可以保证一定不会出现不一致的情况,但会导致系统吞吐量大幅度降低. 解决这 ...