linux社区爱心援助Linux认证系列教程业界动态站务新闻公司招聘网络学院网址大全LPI专题CISCO专题
设为首页
加入收藏
管理团队
JSP  
JAVA  
PERL  
 您的位置:首页 > 开发语言 > asp.net >
栏目导栏
  php
  JSP
  ASP
  asp.net
  JAVA
  c/c++/c#
  perl
  JavaScript
  Basic
  Delphi
资料搜索
热门文章
·NetBPM工作流的一个示例:请假
·Office Web Components(OWC)绘
·asp.net正则表达式语法
·asp.net 2.0 ajax中使用PopupC
·Ado.Net读取Excel常见问题总结
·数据源为空时如何让GridView显
·如何让UpdatePanel支持文件上传
·C#.Net的常见面试试题和参考答
·asp.net ajax客户端编程+jquer
·Brettle.Web.NeatUpload.dll支
·ASP.NET使用Cookie
·ASP.NET DEMO 15: 同时支持行单
·如何使IE的后退按钮无效
·如何在ASP.NET中用OWC绘制图表
·asp.net:正确判断当前用户角色
最新文章
·Ajax Control Toolkit Animati
·讨论一下类似BlogEngine内一次
·使用CSS+SiteMap+UserControl+
·Asp.net中多彩下拉框的实现
·浅谈ASP.NET的Postback
·分清ASP.NET AJAX中的Extender
·Tip:在使用AjaxControlTookit
·有关注册DataItem的一些可能被
·IIRF(Ionic's Isapi Rewrite
·asp.net 客户端回调功能的实现
·关于控件部分的看法--读Progra
·为什么在vista上做开发
·如何封装JS和CSS文件为服务器端
·岂今我看过的最强的排序算法
·设计模式学习笔记之单件模式
Google
 
关于.NET的异常处理的几个误区
[ 作者:  加入时间:2007-10-26 13:17:34  来自:Linux联盟收集整理 ]
很久前就想写这么一篇文章,因为很多人使用.Net多年之后还是对异常处理一知半解的,有很多误解,本文将讲解三个常见误解,一个是catch的使用方法是否正确,另外两个是try/catch的性能损失问题。 HVWLinux联盟
   HVWLinux联盟
  有些人认为下面代码就是一个catch的错误用法: HVWLinux联盟
   HVWLinux联盟
  catch(Exception e) HVWLinux联盟
  { HVWLinux联盟
   throw e; HVWLinux联盟
  } HVWLinux联盟
  首先说明,这不是一个错误用法,但是通常来讲,我们应该避免这种代码。然后要说明的是,这段代码有一个比较典型的作用就是改变异常出现的位置,也就是可以对某类异常统一在一个位置处理。先看下面代码: HVWLinux联盟
   HVWLinux联盟
   public int GetAllCount2() HVWLinux联盟
   { HVWLinux联盟
   try HVWLinux联盟
   { HVWLinux联盟
   openDB(); HVWLinux联盟
   int i = 1; HVWLinux联盟
   return i; HVWLinux联盟
   } HVWLinux联盟
   catch (SqlException sex) HVWLinux联盟
   { HVWLinux联盟
   throw sex; HVWLinux联盟
   } HVWLinux联盟
   catch (Exception ex) HVWLinux联盟
   { HVWLinux联盟
   throw ex; HVWLinux联盟
   } HVWLinux联盟
   } HVWLinux联盟
   public int GetAllCount() HVWLinux联盟
   { HVWLinux联盟
   openDB(); // 这里也可能是微软企业类库等 HVWLinux联盟
   int i = 1; HVWLinux联盟
   return i; HVWLinux联盟
   } HVWLinux联盟
   HVWLinux联盟
   private void openDB() HVWLinux联盟
   { HVWLinux联盟
   conn.Open(); HVWLinux联盟
   } HVWLinux联盟
  假设我们有一个公用方法叫openDB(),而很多方法中调用它,当数据库打开失败的时候,对于调用GetAllCount方法,异常将定位于conn.Open而如果调用GetAllCount2,那么异常定位于throw sex的位置,同时堆栈信息也有所不同,可以更快捷的找到调用方法的位置,也可在此位置进行一些错误恢复处理。尤其是我们编写一些底层类库的时候,比如Framework类库从不会把异常代码定位到Framework类库内部的某个方法上面。但是需要注意的是我们尽量避免捕获异常而不返回,例如 catch(){} HVWLinux联盟
  这样的使用就是典型的错误使用了,因为对于Framework来讲,任何时候系统都可能抛出一个StackOverflowException或者OutOfMemoryExcetpion而上面这段代码则隐藏了这些异常,有时候则导致一些严重的问题。 HVWLinux联盟
   HVWLinux联盟
   HVWLinux联盟
  对于异常处理,在性能上有2点注意 HVWLinux联盟
   HVWLinux联盟
  第一点,在使用try/catch时,如果不发生异常,那么几乎可以忽略性能的损失。 HVWLinux联盟
   HVWLinux联盟
  关于这一点,这里我们进行一些深入分析,对此比较了解的可以跳过本节。首先,让我们先看一下try/catch的IL表现。我们有2个方法,一个使用try/catch,而另一个未做任何处理: HVWLinux联盟
   HVWLinux联盟
  static int Test1(int a, int b) HVWLinux联盟
  { HVWLinux联盟
   try HVWLinux联盟
   { HVWLinux联盟
   if (a > b) HVWLinux联盟
   return a; HVWLinux联盟
   return b; HVWLinux联盟
   } HVWLinux联盟
   catch HVWLinux联盟
   { HVWLinux联盟
   return -1; HVWLinux联盟
   } HVWLinux联盟
  } HVWLinux联盟
   HVWLinux联盟
  static int Test2(int a, int b) HVWLinux联盟
  { HVWLinux联盟
   if (a > b) HVWLinux联盟
   return a; HVWLinux联盟
   return b; HVWLinux联盟
  } HVWLinux联盟
  使用ILDasm工具查看,IL代码分别如下:(这里之所以引入IL,是因为IL是比较接近机器汇编,所以在IL中我们可以更清楚的了解代码的执行情况,对IL没有兴趣的可以跳过此节) HVWLinux联盟
   HVWLinux联盟
   HVWLinux联盟
  .method private hidebysig static int32 Test1(int32 a, HVWLinux联盟
   int32 b) cil managed HVWLinux联盟
  { HVWLinux联盟
   // 代码大小 30 (0x1e) HVWLinux联盟
   .maxstack 2 HVWLinux联盟
   .locals init ([0] int32 CS$1$0000, HVWLinux联盟
   [1] bool CS$4$0001) HVWLinux联盟
   IL_0000: nop HVWLinux联盟
   .try HVWLinux联盟
   { HVWLinux联盟
   IL_0001: nop HVWLinux联盟
   IL_0002: ldarg.0 HVWLinux联盟
   IL_0003: ldarg.1 HVWLinux联盟
   IL_0004: cgt HVWLinux联盟
   IL_0006: ldc.i4.0 HVWLinux联盟
   IL_0007: ceq HVWLinux联盟
   IL_0009: stloc.1 HVWLinux联盟
   IL_000a: ldloc.1 HVWLinux联盟
   IL_000b: brtrue.s IL_0011 HVWLinux联盟
   IL_000d: ldarg.0 HVWLinux联盟
   IL_000e: stloc.0 HVWLinux联盟
   IL_000f: leave.s IL_001b HVWLinux联盟
   IL_0011: ldarg.1 HVWLinux联盟
   IL_0012: stloc.0 HVWLinux联盟
   IL_0013: leave.s IL_001b HVWLinux联盟
   } // end .try HVWLinux联盟
   catch [mscorlib]System.Object HVWLinux联盟
   { HVWLinux联盟
   IL_0015: pop HVWLinux联盟
   IL_0016: nop HVWLinux联盟
   IL_0017: ldc.i4.m1 HVWLinux联盟
   IL_0018: stloc.0 HVWLinux联盟
   IL_0019: leave.s IL_001b HVWLinux联盟
   } // end handler HVWLinux联盟
   IL_001b: nop HVWLinux联盟
   IL_001c: ldloc.0 HVWLinux联盟
   IL_001d: ret HVWLinux联盟
  } // end of method Program::Test1 HVWLinux联盟
   HVWLinux联盟
  Test2 HVWLinux联盟
   HVWLinux联盟
  .method private hidebysig static int32 Test2(int32 a, HVWLinux联盟
   int32 b) cil managed HVWLinux联盟
  { HVWLinux联盟
   // 代码大小 22 (0x16) HVWLinux联盟
   .maxstack 2 HVWLinux联盟
   .locals init ([0] int32 CS$1$0000, HVWLinux联盟
   [1] bool CS$4$0001) HVWLinux联盟
   IL_0000: nop HVWLinux联盟
   IL_0001: ldarg.0 HVWLinux联盟
   IL_0002: ldarg.1 HVWLinux联盟
   IL_0003: cgt HVWLinux联盟
   IL_0005: ldc.i4.0 HVWLinux联盟
   IL_0006: ceq HVWLinux联盟
   IL_0008: stloc.1 HVWLinux联盟
   IL_0009: ldloc.1 HVWLinux联盟
   IL_000a: brtrue.s IL_0010 HVWLinux联盟
   IL_000c: ldarg.0 HVWLinux联盟
   IL_000d: stloc.0 HVWLinux联盟
   IL_000e: br.s IL_0014 HVWLinux联盟
   IL_0010: ldarg.1 HVWLinux联盟
   IL_0011: stloc.0 HVWLinux联盟
   IL_0012: br.s IL_0014 HVWLinux联盟
   IL_0014: ldloc.0 HVWLinux联盟
   IL_0015: ret HVWLinux联盟
  } // end of method Program::Test2 HVWLinux联盟
  这里我们只需关注红字高亮的几行即可。此处我们只关心try区块,即未发生异常的时候,对于Test1来讲,IL代码多出了8个字节来保存catch的处理代码,这一点对性能和资源几乎是微不足道的。 HVWLinux联盟
  我们看到当Test1执行到IL_000f或者IL_0013的时候,将数据出栈并使用leave.s退出try区块转向IL_001b地址,然后将数据入栈并返回。 HVWLinux联盟
   HVWLinux联盟
  对于Test2来讲,执行到IL_000e或者IL_0012的时候, 直接退出,并将数据入栈然后返回。 HVWLinux联盟
   HVWLinux联盟
  这里对几个关键指令简单介绍一下 HVWLinux联盟
   HVWLinux联盟
  nop do noting HVWLinux联盟
  stloc.0 Pop value from stack into local variable 0. HVWLinux联盟
  ldloc.0 Load local variable 0 onto stack. HVWLinux联盟
  br.s target branch to target, short form HVWLinux联盟
  leave.s target Exit a protected region of code, short form HVWLinux联盟
   HVWLinux联盟
  下面我们看代码的实际运行情况,新建一个控制台Console程序,加入下面代码: HVWLinux联盟
   HVWLinux联盟
   点击左边图标展开代码 HVWLinux联盟
  static void Main(string[] args) HVWLinux联盟
  { HVWLinux联盟
   int times = 1000000; //我们将结果放大100,0000倍 HVWLinux联盟
   long l1, l2,l3,l4, s1, s2; HVWLinux联盟
   HVWLinux联盟
   Console.WriteLine("Press any key to continue"); HVWLinux联盟
   Console.Read(); HVWLinux联盟
   HVWLinux联盟
   for (int j = 0; j < 10; j++) HVWLinux联盟
   { HVWLinux联盟
   l1 = DateTime.Now.Ticks; HVWLinux联盟
   HVWLinux联盟
   for (int i = 0; i < times; i++) HVWLinux联盟
   Test2(2, 4); HVWLinux联盟
   HVWLinux联盟
   l2 = DateTime.Now.Ticks; HVWLinux联盟
   s1 = l2 - l1; HVWLinux联盟
   Console.WriteLine("time spent:" + s1); HVWLinux联盟
   HVWLinux联盟
   l3 = DateTime.Now.Ticks; HVWLinux联盟
   HVWLinux联盟
   for (int i = 0; i < times; i++) HVWLinux联盟
   Test1(2, 4); HVWLinux联盟
   HVWLinux联盟
   l4 = DateTime.Now.Ticks; HVWLinux联盟
   s2 = l4 - l3; HVWLinux联盟
   Console.WriteLine("time spent:" + s2); HVWLinux联盟
   Console.WriteLine("difference:" + (s2 - s1) + ", rate:" + (float)(s2 - s1) / s1 / times); HVWLinux联盟
   } HVWLinux联盟
  } HVWLinux联盟
   HVWLinux联盟
  static int Test1(int a, int b) HVWLinux联盟
  { HVWLinux联盟
   try HVWLinux联盟
   { HVWLinux联盟
   for (int i = 0; i < 100; i++) ; // 模拟长时操纵 HVWLinux联盟
   if (a > b) HVWLinux联盟
   return a; HVWLinux联盟
   return b; HVWLinux联盟
   } HVWLinux联盟
   catch HVWLinux联盟
   { HVWLinux联盟
   return -1; HVWLinux联盟
   } HVWLinux联盟
  } HVWLinux联盟
   HVWLinux联盟
  static int Test2(int a, int b) HVWLinux联盟
  { HVWLinux联盟
   for (int i = 0; i < 100; i++) ; // 模拟长时操纵 HVWLinux联盟
   if (a > b) HVWLinux联盟
   return a; HVWLinux联盟
   return b; HVWLinux联盟
  } HVWLinux联盟
  运行后可以看到代码的差异,通常在0.0001%的差别以内。 HVWLinux联盟
   HVWLinux联盟
  第二点,如果发生异常,那么引发或处理异常时,将使用大量的系统资源和执行时间。引发异常只是为了处理确实异常的情况,而不是为了处理可预知的事件或流控制。例如,如果方法参数无效,而应用程序需要使用有效的参数调用方法,则可以引发异常。无效的方法参数意味着出现了异常情况。相反,用户偶尔会输入无效数据,这是可以预见的,因此如果用户输入无效,则不要引发异常。在这种情况下,请提供重试机制以便用户输入有效输入。 HVWLinux联盟
   HVWLinux联盟
  我们经常需要将一个字符串转换为int,比如将Request.QueryString["id"]这样的字符串转换为int,在asp.net 1.x时代,我们常使用下列方式 HVWLinux联盟
   HVWLinux联盟
  try HVWLinux联盟
  { HVWLinux联盟
   int id = Int32.Parse("123"); HVWLinux联盟
  } HVWLinux联盟
  catch(){} HVWLinux联盟
  这样的后果是如果出现转换异常,你将不得不牺牲大量的系统资源来处理异常,即使你没有编写任何异常处理代码。 HVWLinux联盟
   HVWLinux联盟
  当然你也可以编写大量的代码来检测和转换字符串来替代try/catch方式,而从asp.net 2.0以后,框架将这个检测转换过程封装到Int32.TryParse方法中,再也不用蹩脚的try/catch来处理了。 HVWLinux联盟
   HVWLinux联盟
   HVWLinux联盟
  还要补充一点,就是finally中的代码是始终保证运行的,所以留给大家一个问题,下面代码执行后a的值是多少: HVWLinux联盟
   HVWLinux联盟
  int a = 2; HVWLinux联盟
  try HVWLinux联盟
  { HVWLinux联盟
   int i = Int32.Parse("s"); HVWLinux联盟
  } HVWLinux联盟
  catch HVWLinux联盟
  { HVWLinux联盟
   a = 1; HVWLinux联盟
   return; HVWLinux联盟
  } HVWLinux联盟
  finally HVWLinux联盟
  { HVWLinux联盟
   a = 3; HVWLinux联盟
  } HVWLinux联盟
   HVWLinux联盟
   HVWLinux联盟
  小节:本文主要对异常处理的3个常见误解进行了纠正。撰稿仓促,如有疏漏,烦请指出。 HVWLinux联盟
Linux联盟收集整理 ,转贴请标明原始链接,如有任何疑问欢迎来本站Linux论坛讨论
评论】【加入收藏夹】【 】【打印】【关闭
※ 相关链接
 ·.NET和VB编程创建SQL Server  (2007-10-29 14:36:19)
 ·ADO.NET、NBear和NHibernate和IbatisNet简单读写性能比较  (2007-10-29 14:27:18)
 ·如何将asp.net的后台cs代码移动到页面上  (2007-10-29 14:25:45)
 ·.NET 框架中的 Factory 模式  (2007-10-29 14:24:49)
 ·读Programming ASP.NET中文版控件  (2007-10-29 14:15:23)
 ·ASP.NET 2.0如何封装JS和CSS文件为服务器端控件  (2007-10-29 14:13:11)
 ·asp.net中用VML动态的画出数据分析图表详解  (2007-10-29 14:07:23)
 ·asp.net性能的技巧  (2007-10-26 13:23:05)
 ·asp.net多频道网站开发架构浅析  (2007-10-26 13:22:34)
 ·让 SortTable 和 Asp.net Ajax 和睦相处  (2007-10-26 13:21:44)