知识大全 .NET的异常处理的几个误区

Posted

篇首语:卧疾丰暇豫,翰墨时间作。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 .NET的异常处理的几个误区相关的知识,希望对你有一定的参考价值。

.NET的异常处理的几个误区  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

  Net出现多年之后还是对异常处理一知半解的 有很多误解 本文将讲解三个常见误解 一个是catch的使用方法是否正确 另外两个是try/catch的性能损失问题

  有些人认为下面代码就是一个catch的错误用法

  

  catch(Exception e) throw e;

  首先说明 这不是一个错误用法 但是通常来讲 我们应该避免这种代码 然后要说明的是 这段代码有一个比较典型的作用就是改变异常出现的位置 也就是可以对某类异常统一在一个位置处理 先看下面代码

  

  public int GetAllCount () try openDB(); int i = ; return i; catch (SqlException sex) throw sex; catch (Exception ex) throw ex; public int GetAllCount() openDB(); // 这里也可能是微软企业类库等 int i = ; return i; private void openDB() conn Open();

  假设我们有一个公用方法叫openDB() 而很多方法中调用它 当数据库打开失败的时候 对于调用GetAllCount方法 异常将定位于 conn Open而如果调用GetAllCount 那么异常定位于throw sex的位置 同时堆栈信息也有所不同 可以更快捷的找到调用方法的位置 也可在此位置进行一些错误恢复处理 尤其是我们编写一些底层类库的时候 比如 Framework类库从不会把异常代码定位到Framework类库内部的某个方法上面 但是需要注意的是我们尽量避免捕获异常而不返回 例如 catch()

  这样的使用就是典型的错误使用了 因为对于Framework来讲 任何时候系统都可能抛出一个StackOverflowException或者OutOfMemoryExcetpion而上面这段代码则隐藏了这些异常 有时候则导致一些严重的问题

  对于异常处理 在性能上有 点注意

  第一点 在使用try/catch时 如果不发生异常 那么几乎可以忽略性能的损失

  关于这一点 这里我们进行一些深入分析 对此比较了解的可以跳过本节 首先 让我们先看一下try/catch的IL表现 我们有 个方法 一个使用try/catch 而另一个未做任何处理

  

  static int Test (int a int b) try if (a > b) return a; return b; catch return ; static int Test (int a int b) if (a > b) return a; return b;

  使用ILDasm工具查看 IL代码分别如下 (这里之所以引入IL 是因为IL是比较接近机器汇编 所以在IL中我们可以更清楚的了解代码的执行情况 对IL没有兴趣的可以跳过此节)

  

  thod private hidebysig static int Test (int a int b) cil managed // 代码大小 ( x e) maxstack locals init ([ ] int CS$ $ [ ] bool CS$ $ ) IL_ : nop try IL_ : nop IL_ : ldarg IL_ : ldarg IL_ : cgt IL_ : ldc i IL_ : ceq IL_ : stloc IL_ a: ldloc IL_ b: brtrue s IL_ IL_ d: ldarg IL_ e: stloc IL_ f: leave s IL_ b IL_ : ldarg IL_ : stloc IL_ : leave s IL_ b // end try catch [mscorlib]System Object IL_ : pop IL_ : nop IL_ : ldc i m IL_ : stloc IL_ : leave s IL_ b // end handler IL_ b: nop IL_ c: ldloc IL_ d: ret // end of method Program::Test Test thod private hidebysig static int Test (int a int b) cil managed // 代码大小 ( x ) maxstack locals init ([ ] int CS$ $ [ ] bool CS$ $ ) IL_ : nop IL_ : ldarg IL_ : ldarg IL_ : cgt IL_ : ldc i IL_ : ceq IL_ : stloc IL_ : ldloc IL_ a: brtrue s IL_ IL_ c: ldarg IL_ d: stloc IL_ e: br s IL_ IL_ : ldarg IL_ : stloc IL_ : br s IL_ IL_ : ldloc IL_ : ret // end of method Program::Test

  这里我们只需关注红字高亮的几行即可 此处我们只关心try区块 即未发生异常的时候 对于Test 来讲 IL代码多出了 个字节来保存catch的处理代码 这一点对性能和资源几乎是微不足道的

  我们看到当Test 执行到IL_ f或者IL_ 的时候 将数据出栈并使用leave s退出try区块转向IL_ b地址 然后将数据入栈并返回

  对于Test 来讲 执行到IL_ e或者IL_ 的时候 直接退出 并将数据入栈然后返回

  这里对几个关键指令简单介绍一下

  

  nop do noting stloc Pop value from stack into local variable ldloc Load local variable onto stack br s target branch to target short form leave s target Exit a protected region of code short form

  下面我们看代码的实际运行情况 新建一个控制台Console程序 加入下面代码

  

  static void Main(string[] args) int times = ; //我们将结果放大 倍 long l l l l s s ; Console WriteLine( Press any key to continue ); Console Read(); for (int j = ; j < ; j++) l = DateTime Now Ticks; for (int i = ; i < times; i++) Test ( ); l = DateTime Now Ticks; s = l l ; Console WriteLine( time spent: + s ); l = DateTime Now Ticks; for (int i = ; i < times; i++) Test ( ); l = DateTime Now Ticks; s = l l ; Console WriteLine( time spent: + s ); Console WriteLine( difference: +(s s )+ rate: +(float)(s s )/s /times); static int Test (int a int b) try for (int i = ; i < ; i++) ; // 模拟长时操纵 if (a > b) return a; return b; catch return ; static int Test (int a int b) for (int i = ; i < ; i++) ; // 模拟长时操纵 if (a > b) return a; return b;

  运行后可以看到代码的差异 通常在 %的差别以内

  第二点 如果发生异常 那么引发或处理异常时 将使用大量的系统资源和执行时间 引发异常只是为了处理确实异常的情况 而不是为了处理可预知的事件或流控制 例如 如果方法参数无效 而应用程序需要使用有效的参数调用方法 则可以引发异常 无效的方法参数意味着出现了异常情况 相反 用户偶尔会输入无效数据 这是可以预见的 因此如果用户输入无效 则不要引发异常 在这种情况下 请提供重试机制以便用户输入有效输入

  我们经常需要将一个字符串转换为int 比如将Request QueryString[ id ]这样的字符串转换为int 在 x时代 我们常使用下列方式

  

  try int id = Int Parse( ); catch()

  这样的后果是如果出现转换异常 你将不得不牺牲大量的系统资源来处理异常 即使你没有编写任何异常处理代码

  当然你也可以编写大量的代码来检测和转换字符串来替代try/catch方式 而从 以后 框架将这个检测转换过程封装到Int TryParse方法中 再也不用蹩脚的try/catch来处理了

  还要补充一点 就是finally中的代码是始终保证运行的 所以留给大家一个问题 下面代码执行后a的值是多少

  

  int a = ; try int i = Int Parse( s ); catch a = ; return; finally a = ;

cha138/Article/program/net/201311/13168

相关参考

浅谈痤疮认识的几个常见误区

浅谈痤疮认识的几个常见误区!痤疮是我们每个人都很熟悉的皮肤色斑问题。许多因为种种的脸部痤疮形象问题,而羞于出门,整日的泡在家里。更有一些人因为久治不愈的痤疮,严重的影响到生活工作。在此,请专家为您讲解

对放心蔬菜的几个认识误区

能不能吃上放心菜,是百姓居家过日子每天都关心的一个问题。可是对什么蔬菜可以放心食用,消费者往往存在一些误区。误区一:地下根茎类蔬菜最放心一般来说,人们对从地里挖取出来的蔬菜比较放心,因为给蔬菜打药一般

有关心脏病认识的几个误区

来自医院第一线的信息表明,无论在发病率或死亡率方面,心脏病都已跃居于各类疾病之首位,成为名副其实的人类“头号杀手”,而人们对心脏病认识的若干误区又在相当程度上妨碍了对这种严重疾患的防治。误区一:瘦人不

微耕机使用的几个误区

微耕机使用时存在的一些误区,容易造成微耕机故障率偏高。一、新机磨合不到位磨合是一个循序渐进的过程,必须从小油门低转速、低挡位、低负荷开始,逐步加大到高转速、高挡位、大负荷。其目的是在良好的技术条件和润

微耕机使用的几个误区

微耕机使用时存在的一些误区,容易造成微耕机故障率偏高。一、新机磨合不到位磨合是一个循序渐进的过程,必须从小油门低转速、低挡位、低负荷开始,逐步加大到高转速、高挡位、大负荷。其目的是在良好的技术条件和润

知识大全 Java编程语言的几个认识误区

Java编程语言的几个认识误区  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!cha138

传统玉米种植的几个误区

1、凭经验随意设置株行距,不按照玉米品种的特性来调整,对密度没有概念,认为密一点产量会更高。  其实玉米根据植株的大小,密度大小不一,一般2800~4000株左右,播种时一般要按照说明的密度进行播种,

传统玉米种植的几个误区

1、凭经验随意设置株行距,不按照玉米品种的特性来调整,对密度没有概念,认为密一点产量会更高。  其实玉米根据植株的大小,密度大小不一,一般2800~4000株左右,播种时一般要按照说明的密度进行播种,

银屑病治疗的几个误区是什么

银屑病的治疗误区是什么呢?我们知道无论是什么疾病,由于我们对于疾病常识的不认识,常常会发生一些疾病的误诊,或是由于治疗上的误区导致患者疾病恶化。所以我们一定要明确疾病疾病在治疗上的注意事项,那么银屑病

农机操作中的几个常见误区

1、起步猛抬离合器。机车起步时应缓慢地松开离合器踏板,同时适当加大油门行驶。否则,会造成对离合器总成及传动件的冲击,甚至损坏。2、长期脚踏离合器踏板。有些机手在机车行驶中习惯将脚踏在离合器踏板上,其害