在日常项目开发中,异常抛出和捕获是再平常不过的事情。通过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. .get的取值特点:.get只起到取值的作用 不能对原值修改

    #银行支付接口 def pay_interface(username,cost): user_dic=db_handler.select(username) if user_dic.get('bala ...

  2. 计算机等级考试真题1(JAVA)

    答案: 01-05 C D A A C   06-10 B/D    C C C B 11-15 A C A C A 16-20 C B     C    21-25 D D C D D 26-30 ...

  3. 小白的springboot之路(九)、集成MongoDB

    0.前言 MongoDB是一个高性能.开源的文档型数据库,是当前nosql数据库中最热门的一种,在企业中广泛应用:虽然前段时间更改了开源协议导致被很多企业舍弃,但主要是对云服务商影响较大,对我们来说其 ...

  4. PuppeteerSharp读取页面完整HTML(.NetCore)

    1.使用NUGET安装PuppeteerSharp 通过工具或者命令方式安装 2.初始化浏览器 await new BrowserFetcher().DownloadAsync(BrowserFetc ...

  5. 从无到有通过IDEA搭建SpringBoot项目

    本人第一次写博客希望记录当下,努力成为IT界中的清流,写的不好多多包涵. SpringBoot是由Pivotal团队在2013年开始研发.2014年4月发布第一个版本的全新开源的轻量级框架.它基于Sp ...

  6. gitlab如何从Github导入项目

    本文简单演示如何Github上导入项目到私人搭建的Gitlab中,搭建过程参考:CentOS7 搭建gitlab服务器. Gitlab版本是gitlab-ce-12.0.2,界面可能稍有差异,但应该影 ...

  7. scanf和printf格式化输入输出中非常实用的小技巧

    输入输出几乎是每个C程序必须具备的功能,因为有了它们,程序才有了交互性.C提供的输入输出函数除了具有必须的输入输出功能外,还有一些其他实用的小技巧,了解这些小技巧将会为程序带来更友好的用户体验. 一. ...

  8. Java开发中解决Js的跨域问题

    主流方法有JSONP和CORS两种,这里记一下后者的方式,理论基础就是在请求的时候在http请求头中添加如下属性: //指定允许其他域名访问 Access-Control-Allow-Origin:h ...

  9. Flask 特殊装饰器

    请求进入函数之前 before_request # -*- coding: utf-8 -*-   from flask import Flask, session, redirect, reques ...

  10. RESTful 架构风格

    在移动互联网的大潮下,『微服务』的概念也越来越被大家接受并应用于实践,日益增多的web service逐渐统一于RESTful 架构风格,如果开发者对RESTful 架构风格不甚了解,则开发出的所谓R ...