|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
效率会有不少的变化。而实际上java是基于堆栈机器来设计,这和我们常见的基于寄存器的本地机器是差异比较大的。总体来说,这是一种虚拟机的设计思路。<<展示C#>>第七章非常处置(rainbow翻译)
出处:http://www.informit.com/matter/ser0000002
注释:
第七章非常处置
通用言语运转时(CLR)具有的一个很年夜的上风为,非常处置是跨言语被尺度化的。一个在C#中所激发的非常能够在VisualBasic客户中失掉处置。不再有HRESULTs大概ISupportErrorInfo接口。
只管跨言语非常处置的掩盖面很广,但这一章完整会合会商C#非常处置。你稍为改动编译器的溢出处置举动,接着风趣的事变就入手下手了:你处置了该非常。要增添更多的手腕,随后激发你所创立的非常。
7.1校验(checked)和非校验(unchecked)语句
当你实行运算时,有大概会产生盘算了局超越了局变量数据范例的无效局限。这类情形被称为溢出,根据分歧的编程言语,你将被以某种体例关照――大概基本就没有被关照。(C++程序员听起来熟习吗?)
那末,C#怎样处置溢出的呢?要找出其默许举动,请看我在这本书后面提到的阶乘的例子。(为了便利其见,后面的例子再次在清单7.1中给出)
清单7.1盘算一个数的阶乘
1:usingSystem;
2:
3:classFactorial
4:{
5:publicstaticvoidMain(string[]args)
6:{
7:longnFactorial=1;
8:longnComputeTo=Int64.Parse(args[0]);
9:
10:longnCurDig=1;
11:for(nCurDig=1;nCurDig<=nComputeTo;nCurDig++)
12:nFactorial*=nCurDig;
13:
14:Console.WriteLine("{0}!is{1}",nComputeTo,nFactorial);
15:}
16:}
当你象如许利用命令行实行程序时
factorial2000
了局为0,甚么也没有产生。因而,假想C#冷静地处置溢出情形而不明白地告诫你是平安的。
经由过程给全部使用程序(经编译器开关)或于语句级同意溢出校验,你就能够改动这类举动。以下两节分离办理一种计划。
7.1.1给溢出校验设置编译器
假如你想给全部使用程序把持溢出校验,C#编译器设置选择是恰是你所要找的。默许地,溢出校验是禁用的。要明白地请求它,运转以下编译器命令:
cscfactorial.cs/checked+
如今当你用2000参数实行使用程序时,CLR关照你溢出非常(见.1)。
.1 同意了溢出非常,阶乘代码发生了一个非常。
按OK键分开对话框展现了非常信息:
Exceptionoccurred:System.OverflowException
atFactorial.Main(System.String[])
如今你懂得了溢出前提激发了一个System.OverflowException非常。下一节,在我们完成语法校验以后,怎样捕捉并处置所呈现的非常?
7.1.2 语法溢出校验
假如你不想给全部使用程序同意溢出校验,仅给某些代码段同意校验,你大概会很温馨。关于这类场所,你大概象清单7.2中显现的那样,利用校验语句。
清单7.2 阶乘盘算中的溢出校验
1:usingSystem;
2:
3:classFactorial
4:{
5:publicstaticvoidMain(string[]args)
6:{
7:longnFactorial=1;
8:longnComputeTo=Int64.Parse(args[0]);
9:
10:longnCurDig=1;
11:
12:for(nCurDig=1;nCurDig<=nComputeTo;nCurDig++)
13:checked{nFactorial*=nCurDig;}
14:
15:Console.WriteLine("{0}!is{1}",nComputeTo,nFactorial);
16:}
17:}
乃至就如你使用标记checked-编译了该代码,在第13行中,溢出校验仍旧会对乘法完成反省。毛病信息坚持分歧。
显现相反举动的语句长短校验(unchecked)。乃至假如同意了溢出校验(给编译器加上checked+标记),被unchecked语句所括住的代码也将不会激发溢出非常:
unchecked
{
nFactorial*=nCurDig;
}
7.2 非常处置语句
既然你晓得了怎样发生一个非常(你会发明更多的办法,信任我),仍旧存在怎样处置它的成绩。假如你是一个C++WIN32程序员,一定熟习SEH(布局非常处置)。你将从中找到慰藉,C#中的命令几近是不异的,并且它们也以类似的体例运作。
ThefollowingthreesectionsintroduceC#sexception-handlingstatements:
以下三节先容了C#的非常处置语句:
。用try-catch捕捉非常
。用try-finally扫除非常
。用try-catch-finally处置一切的非常
7.2.1 利用try和catch捕捉非常
你一定会对一件事十分感乐趣――不要提醒给用户那使人厌恶的非常动静,以便你的使用程序持续实行。要如许,你必需捕捉(处置)该非常。
如许利用的语句是try和catch。try包括大概会发生非常的语句,而catch处置一个非常,假如有非常存在的话。清单7.3用try和catch为OverflowException完成非常处置。
清单7.3捕捉由FactorialCalculation激发的OverflowException非常
1:usingSystem;
2:
3:classFactorial
4:{
5:publicstaticvoidMain(string[]args)
6:{
7:longnFactorial=1,nCurDig=1;
8:longnComputeTo=Int64.Parse(args[0]);
9:
10:try
11:{
12:checked
13:{
14:for(;nCurDig<=nComputeTo;nCurDig++)
15:nFactorial*=nCurDig;
16:}
17:}
18:catch(OverflowExceptionoe)
19:{
20:Console.WriteLine("Computing{0}causedanoverflowexception",nComputeTo);
21:return;
22:}
23:
24:Console.WriteLine("{0}!is{1}",nComputeTo,nFactorial);
25:}
26:}
为了申明分明,我扩大了某些代码段,并且我也包管非常是由checked语句发生的,乃至当你健忘了编译器设置时。
正如你所见,非常处置其实不贫苦。你一切要做的是:在try语句中包括简单发生非常的代码,接着捕捉非常,该非常在这个例子中是OverflowException范例。不管一个非常甚么时分被激发,在catch段里的代码会注重举行得当的处置。
假如你不事前晓得哪种非常会被预期,而仍旧想处于平安形态,复杂地疏忽非常的范例。
try
{
...
}
catch
{
...
}
可是,经由过程这个路子,你不克不及取得对非常工具的会见,而该工具含有主要的堕落信息。一样平常化非常处置代码象如许:
try
{
...
}
catch(System.Exceptione)
{
...
}
注重,你不克不及用ref或out润色符传送e工具给一个办法,也不克不及赋给它一个分歧的值。
7.2.2利用try和finally扫除非常
假如你更体贴扫除而不是毛病处置,try和finally会取得你的喜好。它不但克制了堕落动静,并且一切包括在finally块中的代码在非常被激发后仍旧会被实行。
只管程序不一般停止,但你还能够为用户猎取一条动静,如清单7.4所示。
清单7.4在finally语句中处置非常
1:usingSystem;
2:
3:classFactorial
4:{
5:publicstaticvoidMain(string[]args)
6:{
7:longnFactorial=1,nCurDig=1;
8:longnComputeTo=Int64.Parse(args[0]);
9:boolbAllFine=false;
10:
11:try
12:{
13:checked
14:{
15:for(;nCurDig<=nComputeTo;nCurDig++)
16:nFactorial*=nCurDig;
17:}
18:bAllFine=true;
19:}
20:finally
21:{
22:if(!bAllFine)
23:Console.WriteLine("Computing{0}causedanoverflowexception",nComputeTo);
24:else
25:Console.WriteLine("{0}!is{1}",nComputeTo,nFactorial);
26:}
27:}
28:}
经由过程检测该代码,你大概会猜到,即便没有激发非常处置,finally也会被实行。这是真的――在finally中的代码老是会被实行的,不论是否具有非常前提。为了举例申明怎样在两种情形下供应一些成心义的信息给用户,我引进了新变量bAllFine。bAllFine告知finally语段,它是不是是由于一个非常大概仅是由于盘算的顺遂完成而被挪用。
作为一个习气了SEH程序员,你大概会想,是不是有一个与__leave语句等价的语句,该语句在C++中很管用。假如你还不懂得,在C++中的__leave语句是用来提早停止try语段中的实行代码,并当即跳转到finally语段。
坏动静,C#中没有__leave语句。可是,在清单7.5中的代码演示了一个你能够完成的计划。
清单7.5从try语句跳转到finally语句
1:usingSystem;
2:
3:classJumpTest
4:{
5:publicstaticvoidMain()
6:{
7:try
8:{
9:Console.WriteLine("try");
10:goto__leave;
11:}
12:finally
13:{
14:Console.WriteLine("finally");
15:}
16:
17:__leave:
18:Console.WriteLine("__leave");
19:}
20:}
当这个使用程序运转时,输入了局为
try
finally
__leave
一个goto语句不克不及加入一个finally语段。乃至把goto语句放在try语句段中,仍是会当即前往把持到finally语段。因而,goto只是分开了try语段并跳转到finally语段。直到finally中的代码完成运转后,才干抵达__leave标签。按这类体例,你能够仿照在SEH中利用的的__leave语句。
特地地,你大概嫌疑goto语句被疏忽了,由于它是try语句中的最初一条语句,而且把持主动地转移到了finally。为了证实不是如许,试把goto语句放到Console.WriteLine办法挪用之前。只管因为不成抵达代码你失掉了编译器的告诫,可是你将看到goto语句实践上被实行了,且没无为try字符串发生的输入。
7.2.3利用try-catch-finally处置一切非常
使用程序最有大概的路子是兼并后面两种毛病处置手艺――捕捉毛病、扫除并持续实行使用程序。一切你要做的是在堕落处置代码中利用try、catch和finally语句。清单7.6显现了处置零除毛病的路子。
清单7.6完成多个catch语句
1:usingSystem;
2:
3:classCatchIT
4:{
5:publicstaticvoidMain()
6:{
7:try
8:{
9:intnTheZero=0;
10:intnResult=10/nTheZero;
11:}
12:catch(DivideByZeroExceptiondivEx)
13:{
14:Console.WriteLine("dividebyzerooccurred!");
15:}
16:catch(ExceptionEx)
17:{
18:Console.WriteLine("someotherexception");
19:}
20:finally
21:{
22:}
23:}
24:}
这个例子的技能为,它包括了多个catch语句。第一个捕捉了更大概呈现的DivideByZeroException非常,而第二个catch语句经由过程捕捉一般非常处置了一切剩上去的非常。
你一定老是起首捕捉特定的非常,接着是一般的非常。假如你不按这个按次捕捉非常,会产生甚么事呢?清单7.7中的代码有申明。
清单7.7按次不得当的catch语句
1:try
2:{
3:intnTheZero=0;
4:intnResult=10/nTheZero;
5:}
6:catch(ExceptionEx)
7:{
8:Console.WriteLine("exception"+Ex.ToString());
9:}
10:catch(DivideByZeroExceptiondivEx)
11:{
12:Console.WriteLine("nevergoingtoseethat");
13:}
编译器将捕捉到一个小毛病,并相似如许呈报该毛病:
wrongcatch.cs(10,9):errorCS0160:Apreviouscatchclausealready
catchesallexceptionsofthisorasupertype(System.Exception)
最初,我必需告密CLR非常与SEH比拟时的一个弱点(或不同):没有EXCEPTION_CONTINUE_EXECUTION标识符的等价物,它在SEH非常过滤器中很有效。基础上,EXCEPTION_CONTINUE_EXECUTION同意你从头实行卖力非常的代码片断。在从头实行之前,你无机会变动变量等。我团体出格喜好的手艺为,利用会见背例非常,按必要实行内存分派。
7.3激发非常
当你必需捕捉非常时,其别人起首必需起首可以激发非常。并且,不但其别人可以激发,你也能够卖力激发。其相称复杂:
thrownewArgumentException("Argumentcantbe5");
你所必要的是throw语句和一个得当的非常类。我已从表7.1供应的清单当选出一个非常给这个例子。
表7.1Runtime供应的尺度非常
非常范例形貌
Exception一切非常工具的基类
SystemException运转时发生的一切毛病的基类
IndexOutOfRangeException当一个数组的下标超越局限时运转时激发
NullReferenceException当一个空工具被援用时运转时激发
InvalidOperationException当对办法的挪用对工具确当前形态有效时,由某些办法激发
ArgumentException一切参数非常的基类
ArgumentNullException在参数为空(不同意)的情形下,由办法激发
ArgumentOutOfRangeException当参数不在一个给定局限以内时,由办法激发
InteropException方针在或产生在CLR表面情况中的非常的基类
ComException包括COM类的HRESULT信息的非常
SEHException封装win32布局非常处置信息的非常
但是,在catch语句的外部,你已有了随便处理的非常,就不用创立一个新非常。大概在表7.1中的非常没有一个切合你特别的请求――为何不创立一个新的非常?期近将要学到大节中,都触及到这两个话题。
7.3.1从头激发非常
当处于一个catch语句的外部时,你大概决意激发一个今朝正在再度处置的非常,留下进一步的处置给一些内部的try-catch语句。该办法的例子如清单7.8所示。
清单7.8从头激发一个非常
1:try
2:{
3:checked
4:{
5:for(;nCurDig<=nComputeTo;nCurDig++)
6:nFactorial*=nCurDig;
7:}
8:}
9:catch(OverflowExceptionoe)
10:{
11:Console.WriteLine("Computing{0}causedanoverflowexception",nComputeTo);
12:throw;
13:}
注重,我不用划定所声明的非常变量。只管它是可选的,但你也能够如许写:
throwoe;
如今偶然还必需寄望这个非常。
7.3.2创立本人的非常类
只管倡议利用预界说的非常类,但关于实践场所,创立本人的非常类大概会便利。创立本人的非常类,同意你的非常类的利用者依据该非常类接纳分歧的手腕。
在清单7.9中呈现的非常类MyImportantException遵守两个划定规矩:第一,它用Exception停止类名。第二,它完成了一切三个被保举的通用布局。你也应当恪守这些划定规矩。
清单7.9完成本人的非常类MyImportantException
1:usingSystem;
2:
3:publicclassMyImportantException:Exception
4:{
5:publicMyImportantException()
6::base(){}
7:
8:publicMyImportantException(stringmessage)
9::base(message){}
10:
11:publicMyImportantException(stringmessage,Exceptioninner)
12::base(message,inner){}
13:}
14:
15:publicclassExceptionTestApp
16:{
17:publicstaticvoidTestThrow()
18:{
19:thrownewMyImportantException("somethingbadhashappened.");
20:}
21:
22:publicstaticvoidMain()
23:{
24:try
25:{
26:ExceptionTestApp.TestThrow();
27:}
28:catch(Exceptione)
29:{
30:Console.WriteLine(e);
31:}
32:}
33:}
正如你所看到的,MyImportantException非常类不克不及完成任何特别的功效,但它完整基于System.Exception类。程序的残剩部分测试新的非常类,给System.Exception类利用一个catch语句。
假如没有特别的完成而只是给MyImportantException界说了三个机关函数,创立它又有甚么意义呢?它是一个主要的范例――你能够在catch语句中利用它,取代更加一般的非常类。大概激发你的新非常的客户代码能够按划定的catch代码发扬感化。
当利用本人的名字空间编写一个类库时,也要把非常放到该名字空间。只管它并没有呈现在这个例子中,你仍是应当利用得当的属性,为扩大了的毛病信息扩大你的非常类。
7.4非常处置的“要”和“不要”
作为最初的忠言之语,这里是对非常激发和处置所要做和不要做的清单:
。当激发非常时,要供应成心义的文本。
。要激发非常仅当前提是真正非常;也就是当一个一般的前往值不满意时。
。假如你的办法或属性被传送一个坏参数,要激发一个ArgumentException非常。
。当挪用操纵不合适工具确当前形态时,要激发一个InvalidOperationException非常。
。要激发最合适的非常。
。要利用链接非常,它们同意你跟踪非常树。
。不要为一般或预期的毛病利用非常。
。不要为流程的一般把持利用非常。
。不要在办法中激发NullReferenceException或IndexOutOfRangeException非常。
7.5小结
这一章由先容溢出校验入手下手。你可使用编译器开关(默许是关),使全部使用程序同意或克制溢出校验。假如必要微调把持,你可使用校验和非校验语句,它同意你利用或不利用溢出校验来实行一段代码,只管没有给使用程序设置开关。
当产生溢出时,一个非常就被激发了。怎样处置非常取决于你。我提出了各类路子,包含你最有大概贯串全部使用程序利用的:try、catch和finally语句。在陪伴的多个例子中,你学到了它与WIN32布局非常处置(SEH)的不同。
非常处置是给类的用户;但是,假如你卖力创立新的类,就能够激发非常。有多种选择:激发早已捕捉的非常,激发存在的框架非常,大概按划定的实践方针创立新的非常类。
最初,你必要浏览激发和处置非常的各类“要”和
[img=1border=0style=,1src=]http://www.ckuyun.com/[/img]
Java欺骗了我们那么多年,如今的多核时代,我认为它气数已尽! |
|