在日常项目开发中,异常抛出和捕获是再平常不过的事情。通过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. django基础之day04,聚合查询和分组查询

    聚合查询: 聚合函数必须用在分组之后,没有分组其实默认整体就是一组 Max Min Sum Avg Count 1.分组的关键字是:aggretate 2.导入模块 from django.db.mo ...

  2. IIS中部署网站

    1.安装开IIS,打开IIS(Win+R -->inetmgr.exe) 2.进入IIS主界面,右键网站,选择“添加网站”. 3.在“添加网站”对话框中,添加网站名称. 4.点击应用程序池选择, ...

  3. ES6 promise 使用示例

    new Promise(function (resolve, reject) { $.ajax({ type : 'post', data : formData, dataType : 'json', ...

  4. 字符串的扩展(ES6)

    文章目录 字符串的扩展 1. 字符的Unicode表示法 2. codePointAt() 3. String.fromCodePoint() 4. 字符串的遍历器接口 5. at()(提案) 6. ...

  5. d3.js 入门指南 - 仪表盘

    D3的全称是Data-Driven Documents(数据驱动的文档),是一个用来做数据可视化的JavaScript函数库,而JavaScript文件的后缀通常为.js,所以D3被称为D3.js. ...

  6. 远程桌面MATLAB启动失败问题解决

    博客:博客园 | CSDN | blog 远程桌面打开MATLAB会报错,解决办法,打开matlab的licenses路径,如matlab/R2017b/licenses/,路径下存有license文 ...

  7. c++-重载运算符(+-,++,--,+=,-=,cin,cout)

    操作符重载 自定义类型需要操作符重载 运算符重载入门技术推演 友元函数和成员函数实现2元运算符重载 友元函数和成员函数实现1元运算符重载(前置++,前置--,后置++,后置--) 友元函数实现运算符重 ...

  8. JVM调优之服务内存超过阈值报警

    今早收到一条短信,具体报警信息如下: [UMP JVM监控内存报警]应用名:发券worker(jdos_couponwkr);KEY[coupon.send.worker.jvm],主机名:[host ...

  9. js (单个的)点击式下拉菜单

    <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...

  10. koa2使用es7 的装饰器decorator

    本文主要讲述我在做项目中使用装饰器(decorator)来动态加载koa-router的路由的一个基础架构. 目前JavaScript 对decorator 是不支持,但是可以用babel 来编译 既 ...