在日常项目开发中,异常抛出和捕获是再平常不过的事情。通过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. 在MySQL中group by 是什么意思

    mysql语法中group by是什么意思? 在百度中搜索半天,最后找到一篇解释比较好的(不是博文,是百度知道,很郁闷那么多网友怎么就没人解释的清楚),链接如下: http://zhidao.baid ...

  2. [译]C# 7系列,Part 9: ref structs ref结构

    原文:https://blogs.msdn.microsoft.com/mazhou/2018/03/02/c-7-series-part-9-ref-structs/ 背景 在之前的文章中,我解释了 ...

  3. OurEDA慕课网开发记录

    项目说明 OurEDA实验室每年都会面向大一新生招人,每周的沙龙都会有学长来讲课,传经验,录下来的沙龙视频就非常有价值,因此,在老师的安排下,我负责开发了慕课网这样一个项目. 首要问题及其解决方案 视 ...

  4. 分布式事物 - 基于RPC调用 - 补偿模式

    前提 所有服务均有独立的事物管理机制,相互间没有任何关联. 所有业务接口都有对应的补偿方法,用于将已经更新的数据还原到上一次的状态. 本次实例为同步业务,理想状态下,只有全部成功或全部失败两种情况. ...

  5. linux 用户,组

    权限: 所谓的权限是,由用户启动的进程,或者由操作系统启动的进程,可以访问哪些文件,不可以访问哪些文件. 进程太多了,不可能为每个进程定义权限对吧,所以进程的权限来自于启动进程的用户. 用户有哪些权限 ...

  6. ASP.NET Core on K8S深入学习(11)K8S网络知多少

    本篇已加入<.NET Core on K8S学习实践系列文章索引>,可以点击查看更多容器化技术相关系列文章. 一.Kubernetes网络模型 我们都知道Kubernetes作为容器编排引 ...

  7. Python连载57- 邮件头和主题、解析邮件

    一.添加邮件头,抄送等信息 1.mail["From"]表示发送者信息,包括姓名和邮件 2.mail["To"]表示接收者信息,包括姓名和邮件地址 3.mail ...

  8. Http中URI协议 和URL协议的区别和联系

    虽然说URL和URI是整个网络协议栈很常用的东西.可是,假如你去面试求职者其中的差别,估计十个人有八个人答复不上来. 想要熟悉基础知识的朋友最好还是看一下我这个文章. “A Uniform Resou ...

  9. opengl画不出直线 线段 坐标轴 却能画出其他图形的坑

    原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/12054507.html 好多次都是画坐标轴的三条直线画不出来,虽然最后都解决了  但是还是耽误 ...

  10. ARTS改版啦,在改变中前行

    这次打卡,稍微进行了一次改版,在算法和英文文档上进行了拆分,具体的内容在前两天的文章里已经输出,所以在这篇上针对这两块做了一个汇总. 当然,技巧方面的还是在这里先输出,后续再考虑整改吧.循序渐进地上升 ...