马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
听03很多师兄说主讲老师杭城方讲课很差就连旁听也没有去了)Truly
日期:2007.8.5
好久前就想写这么一篇文章,由于良多人利用.Net多年以后仍是对非常处置一孔之见的,有良多曲解,本文将解说三个罕见曲解,一个是catch的利用办法是不是准确,别的两个是try/catch的功能丧失成绩。
有些人以为上面代码就是一个catch的毛病用法:
catch(Exceptione)
{
throwe;
}起首申明,这不是一个毛病用法,可是一般来说,我们应当制止这类代码。然后要申明的是,这段代码有一个对照典范的感化就是改动非常呈现的地位,也就是能够对某类非常一致在一个地位处置。先看上面代码:
publicintGetAllCount2()
{
try
{
openDB();
inti=1;
returni;
}
catch(SqlExceptionsex)
{
throwsex;
}
catch(Exceptionex)
{
throwex;
}
}
publicintGetAllCount()
{
openDB();//这里也多是微软企业类库等
inti=1;
returni;
}
privatevoidopenDB()
{
conn.Open();
}
假定我们有一个公用办法叫openDB(),而良多办法中挪用它,当数据库翻开失利的时分,关于挪用GetAllCount办法,非常将定位于conn.Open而假如挪用GetAllCount2,那末非常定位于throwsex的地位,同时仓库信息也有所分歧,能够更快速的找到挪用办法的地位,也可在此地位举行一些毛病恢复处置。特别是我们编写一些底层类库的时分,好比Framework类库从不会把非常代码定位到Framework类库外部的某个办法下面。可是必要注重的是我们只管制止捕捉非常而不前往,比方catch(){}如许的利用就是典范的毛病利用了,由于关于Framework来说,任什么时候候体系都大概抛出一个StackOverflowException大概OutOfMemoryExcetpion而下面这段代码则埋没了这些非常,偶然候则招致一些严峻的成绩。
关于非常处置,在功能上有2点注重
第一点,在利用try/catch时,假如不产生非常,那末几近能够疏忽功能的丧失。
关于这一点,这里我们举行一些深切剖析,对此对照懂得的能够跳过本节。起首,让我们先看一下try/catch的IL体现。我们有2个办法,一个利用try/catch,而另外一个未做任那边理:
staticintTest1(inta,intb)
{
try
{
if(a>b)
returna;
returnb;
}
catch
{
return-1;
}
}
staticintTest2(inta,intb)
{
if(a>b)
returna;
returnb;
}利用ILDasm工具检察,IL代码分离以下:(这里之以是引进IL,是由于IL是对照靠近呆板汇编,以是在IL中我们能够更分明的懂得代码的实行情形,对IL没有乐趣的能够跳过此节)
.methodprivatehidebysigstaticint32Test1(int32a,
int32b)cilmanaged
{
//代码巨细30(0x1e)
.maxstack2
.localsinit([0]int32CS$1$0000,
[1]boolCS$4$0001)
IL_0000:nop
.try
{
IL_0001:nop
IL_0002:ldarg.0
IL_0003:ldarg.1
IL_0004:cgt
IL_0006:ldc.i4.0
IL_0007:ceq
IL_0009:stloc.1
IL_000a:ldloc.1
IL_000b:brtrue.sIL_0011
IL_000d:ldarg.0
IL_000e:stloc.0
IL_000f:leave.sIL_001b
IL_0011:ldarg.1
IL_0012:stloc.0
IL_0013:leave.sIL_001b
}//end.try
catch[mscorlib]System.Object
{
IL_0015:pop
IL_0016:nop
IL_0017:ldc.i4.m1
IL_0018:stloc.0
IL_0019:leave.sIL_001b
}//endhandler
IL_001b:nop
IL_001c:ldloc.0
IL_001d:ret
}//endofmethodProgram::Test1
Test2
.methodprivatehidebysigstaticint32Test2(int32a,
int32b)cilmanaged
{
//代码巨细22(0x16)
.maxstack2
.localsinit([0]int32CS$1$0000,
[1]boolCS$4$0001)
IL_0000:nop
IL_0001:ldarg.0
IL_0002:ldarg.1
IL_0003:cgt
IL_0005:ldc.i4.0
IL_0006:ceq
IL_0008:stloc.1
IL_0009:ldloc.1
IL_000a:brtrue.sIL_0010
IL_000c:ldarg.0
IL_000d:stloc.0
IL_000e:br.sIL_0014
IL_0010:ldarg.1
IL_0011:stloc.0
IL_0012:br.sIL_0014
IL_0014:ldloc.0
IL_0015:ret
}//endofmethodProgram::Test2这里我们只需存眷红字高亮的几行便可。此处我们只体贴try区块,即未产生非常的时分,关于Test1来说,IL代码多出了8个字节来保留catch的处置代码,这一点对功能和资本几近是微乎其微的。
我们看到当Test1实行到IL_000f大概IL_0013的时分,将数据出栈并利用leave.s加入try区块转向IL_001b地点,然后将数据进栈并前往。
关于Test2来说,实行到IL_000e大概IL_0012的时分,间接加入,并将数据进栈然后前往。
这里对几个关头指令复杂先容一下
nopdonoting
stloc.0Popvaluefromstackintolocalvariable0.
ldloc.0Loadlocalvariable0ontostack.
br.stargetbranchtotarget,shortform
leave.stargetExitaprotectedregionofcode,shortform
上面我们看代码的实践运转情形,新建一个把持台Console程序,到场上面代码:
<br>
<br>点击右边图标睁开代码
staticvoidMain(string[]args)
{
inttimes=1000000;//我们将了局缩小100,0000倍
longl1,l2,l3,l4,s1,s2;
Console.WriteLine("Pressanykeytocontinue
<br>");
Console.Read();
for(intj=0;j<10;j++)
{
l1=DateTime.Now.Ticks;
for(inti=0;i<times;i++)
Test2(2,4);
l2=DateTime.Now.Ticks;
s1=l2-l1;
Console.WriteLine("timespent:"+s1);
l3=DateTime.Now.Ticks;
for(inti=0;i<times;i++)
Test1(2,4);
l4=DateTime.Now.Ticks;
s2=l4-l3;
Console.WriteLine("timespent:"+s2);
Console.WriteLine("difference:"+(s2-s1)+",rate:"+(float)(s2-s1)/s1/times);
}
}
staticintTest1(inta,intb)
{
try
{
for(inti=0;i<100;i++);//摹拟长时利用
if(a>b)
returna;
returnb;
}
catch
{
return-1;
}
}
staticintTest2(inta,intb)
{
for(inti=0;i<100;i++);//摹拟长时利用
if(a>b)
returna;
returnb;
}运转后能够看到代码的差别,一般在0.0001%的不同之内。
第二点,假如产生非常,那末激发或处置非常时,将利用大批的体系资本和实行工夫。激发非常只是为了处置的确非常的情形,而不是为了处置可预知的事务或流把持。比方,假如办法参数有效,而使用程序必要利用无效的参数挪用办法,则能够激发非常。有效的办法参数意味着呈现了非常情形。相反,用户偶然会输出有效数据,这是能够预感的,因而假如用户输出有效,则不要激发非常。在这类情形下,请供应重试机制以便用户输出无效输出。
我们常常必要将一个字符串转换为int,好比将Request.QueryString["id"]如许的字符串转换为int,在asp.net1.x时期,我们常利用以下体例
try
{
intid=Int32.Parse("123");
}
catch(){}如许的成果是假如呈现转换非常,你将不能不就义大批的体系资本来处置非常,即便你没有编写任何非常处置代码。
固然你也能够编写大批的代码来检测和转换字符串来替换try/catch体例,而从asp.net2.0今后,框架将这个检测转换历程封装到Int32.TryParse办法中,不再用糟糕的try/catch来处置了。
还要增补一点,就是finally中的代码是一直包管运转的,以是留给人人一个成绩,上面代码实行后a的值是几:
inta=2;
try
{
inti=Int32.Parse("s");
}
catch
{
a=1;
return;
}
finally
{
a=3;
}
大节:本文次要对非常处置的3个罕见曲解举行了改正。撰稿仓皇,若有疏漏,烦请指出。
参考文献:
http://msdn2.microsoft.com/zh-cn/library/system.exception(VS.80).aspx
http://msdn.microsoft.com/library/chs/default.asp?url=/library/CHS/cpguide/html/cpconexceptionsoverview.asp
《CILInstructionSetSpecification》
《AppliedMicrosoft.NETFrameworkProgramming》
批评:
#re:关于.NET的非常处置的几个误区[未登录]2007-08-0520:15|Lucifer
这个在JefferyRichter的CLRviaC#中解说的充足分明,人人能够往浏览一下!
很遗憾的是楼主的
catch(Exceptione)
{
throwe;
}
在.NET1.x版本中不克不及捕获不切合CLS的非常。而在.NET2.0中固然可以捕获一切非常,却会改动非常的肇端点。FxCop会呈报这是个毛病。
假如你要从头抛出非常,倡议接纳
catch(Exceptione)
{
throw;
}
下面的这段代码固然也会修正非常的肇端点,可是CLR却晓得原始非常被抛出时的仓库地位。
别的,非常带来的优点远远凌驾它会带来的功能丧失。#re:关于.NET的非常处置的几个误区2007-08-0520:32|寸芒
楼上的,我有贰言,固然throwe是抛出新的非常,可是这个新的非常对象仍是本来的非常。就算你在这个子catch里改动了这个非常!#re:关于.NET的非常处置的几个误区[未登录]2007-08-0520:52|Lucifer
@寸芒
我批准你的概念。
实践上,这两段代码的区分就在于CLR怎样断定非常抛出的肇端点。
可是,假如你要用throwe。FxCop就会报错。
以是,仍是保举
catch(Exceptione)
{
throw;
}
而这类捕捉一切非常再次从头抛出的举动长短常稀有的。
#re:关于.NET的非常处置的几个误区2007-08-0608:35|AndersCui
倡议:
只管不要catch像Exception如许的通用非常类;
利用throw来保护非常仓库;
假如要抛出新的非常,能够将本来的非常定为外部非常;
利用try-parse形式时注重,假如由于try操纵以外的缘故原由招致操纵失利,仍应抛出非常;
#re:关于.NET的非常处置的几个误区2007-08-0609:35|BruceLee
非常处置一向用欠好,详细是甚么,但愿总结下。
#re:关于.NET的非常处置的几个误区2007-08-0610:08|Truly
呵呵,起首看到人人积极讲话,甚感欣喜,有些人也做了深切思索,这都很好,起到了举一反三的效果。
特地说一下,下面2位的定见基础上跟我的文中所述并没有甚么收支,制止利用,改动非常地位,制止捕捉一切非常等等这都是人人承认的概念。
别的,CLRviaC#现实上就是我文中提到的参考文献中的《AppliedMicrosoft.NETFrameworkProgramming》,在撰写此文的时分,我又再次审读了非常处置一章,不外仍是感谢你的留言。
同时,我也注重到Asp.NET1.x到Asp.NET2.0今后,非常有所分歧,这一点我在测试那段代码的时分也注重到了,可是详细细节我没有往穷究。#re:关于.NET的非常处置的几个误区2007-08-0610:35|Truly
关于一篇手艺文章而言,可以留给读者一些思索空间长短常好的,明显本文到达了这一目标。关于手艺,我也力争制止引诱、误导读者,多半情形我们剖析道理,研讨框架。这里剖析出了try/catch时的情形,至于孰优孰劣,大概是长处多仍是弱点多,这就交给读者见仁见智,我不喜好教条式的论道本文链接:http://www.ckuyun.com/Truly/archive/2007/08/05/843837.htmlC#中有两处地方用到new关键字,第一处也是最常见的一处是用在调用构造函数的时候,这种情况也是大家见的最多的一种。另一处是用在派生类中,作用有隐藏成员,切断继承关系等,相信第二处的用法大家明显要比第一处生疏。 |