资源描述
单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,*,第,8,章 异常处理,8.1,异常简介,8.2,引发异常,8.3,异常的捕捉及处理,8.4 finally,语句,8.5,关键字,checked,和,unchecked,8.6,习题,8.1,异常简介,数学运算中,被零除是一个错误。在,C#,语言中,当除数和被除数中有一个是,float,或,double,型数被零除将返回一个,PositiveInfinity,(正无穷大)值;当,一个负,float,或,double,型数被零除将返回一个,NegativeInfinity,(负无穷大)值;当,一个值为零的,float,或,double,型数被零除将返回一个,NaN,(不是数字)值。,其中,PositiveInfinity,、,egativeInfinity,、,NaN,都是常量,它们在结构,System.Single,和,System.Double,中均有定义。,8.1,异常简介(续),例:,double d1=10/0.0;,/,值为,PositiveInfinity,double d2=0.0/0;,/,值为,NaN,float f=-1f/0;,/,值为,NegativeInfinity,8.1,异常简介(续),一个整数被零(零的类型为整数类型)除被认为一个错误。当除数是一个整数常量时,这种错误能被编译器发现。,int,i=10/0;,/,编译错误,int,d=10;,d=d/0;,/,编译错误,当除数是一个变量时,编译器并不能发现这种错误。这种错误只会在运行时表现出来。,8.1,异常简介(续),除法运算表达式中的操作数有一个是,decimal,型时,被零除也被认为是一个错误。不过,只有参与这种除法运算的两个操作数都是常量时,被零除的错误才能被编译器发现,否则,这种错误只会在运行时表现出来。,例,8-1,被零除异常,源代码,运 行,例,8-1,被零除异常,using,System;,class,DivideByZero,static,void,Main(),int,i,j,k;,i=1;,j=0;,Console,.WriteLine(i,);,Console,.WriteLine(j,);,k=i/j;,Console,.WriteLine(k,);,8.1,异常简介(续),异常是指程序运行过程中出现的非正常事件。是程序错误的一种。为保证程序安全运行,程序中需要对可能出现的异常进行相应的处理。,C#,语言的异常处理机制可以将具体操作代码和异常处理代码分开,在一个地方集中处理异常。,C#,语言的异常都是异常类的对象。框架类库中预定义了大量的异常类,每个异常类代表了一种异常错误。,每当,C#,程序出现运行错误时,系统就会创建一个相应的异常类对象(即异常)并引发。,8.1,异常简介(续),Exception,:,所有异常的基类,SystemException,:,框架类库中预定义异常的基类,ApplicationException,:,发生非致命应用程序错误时引发的异常,ArgumentException,:,所有参数异常的基类,ArgumentNullException,:,由不允许参数为空的方法引发,ArgumentOutOfRangeException,:,由验证参数是否位于给定范围内的方法引发,8.1,异常简介(续),ArithmeticException,:,在算术运算期间发生的异常的基类,ArrayTypeMismatchException,:,当数组存储给定的元素时,如果由于该元素的实际类型与数组的实际类型不兼容而导致存储失败,就会引发此异常,DivideByZeroException,:,在试图用零除整数或,decimal,值时引发,IndexOutOfRangeException,:,在试图为数组设置小于零或超出数组界限的索引时引发,InvalidCastException,:,当从基类型到接口或派生类型的显式转换在运行时失败时,就会引发此异常,8.1,异常简介(续),IOException,:,发生,I/O,错误时引发的异常,NullReferenceException,:,在需要使用引用对象的场合,如果使用,null,引用,就会引发此异常,OutOfMemoryException,:,在尝试通过,new,分配内存失败时引发,OverflowException,:,在,checked,上下文中的算术运算溢出时引发,StackOverflowException,:,当执行堆栈由于具有太多的挂起方法调用而耗尽时,就会引发此异常,8.1,异常简介(续),异常类都定义有下述属性:,Message,/,获取描述当前异常的消息,StackTrace,/,获取当前异常发生时调用堆栈上的状态,8.1,异常简介(续),Exception,类的常用构造函数:,public Exception(),public,Exception(string,message,),其中参数,string message,,通常用于描述该异常,8.1,异常简介(续),ArgumentException,异常类:,ParamName,/,属性,获取导致该异常的参数的名称,public,ArgumentException,(string message,string,paramName,),/,使用指定的异常信息和导致该异常的参数的名称来初始化异常,8.1,异常简介(续),ArgumentException,派生类中的构造函数定义与,ArgumentException,类有所不同,比如:,public,ArgumentOutOfRangeException,(string,paramName,),/,使用导致该异常的参数的名称来初始化异常,public,ArgumentOutOfRangeException,(string,paramName,string,message),/,使用导致该异常的参数的名称和异常信息来初始化异常,8.1,异常简介(续),自定义异常类应该派生于,System.ApplicationException,类。,例如:,class,MyException,:,System.ApplicationException,public,MyException,(),public,MyException(string,str):base(str,),8.2,引发异常,框架类库定义的标准异常,由系统自动引发。其他异常,则必须在程序中利用关键字,throw,显式引发。例:,static,int,Method(int,a,int,b),if(a,0)throw new,MyException,(,被除数不能小于零,);,if(b,=0)throw new,DivideByZeroException,(,除数不能等于零,);,int,c=a/b;,return c;,using,System;,class,MyException,:,System.,ApplicationException,public,MyException,(),public,MyException(,string,str,):,base,(str,),class,DivideByZero,static,int,Method(,int,a,int,b),if,(a 0),throw,new,MyException,(,被除数不能小于零,);,if,(b=0),throw,new,DivideByZeroException,(,除数不能等于零,);,int,c=a/b;,return,c;,static,void,Main(),int,a=-3,b=0;,int,c=,Method(a,b,);,using,System;,class,MyException,:,System.,ApplicationException,public,MyException,(),public,MyException(,string,str,):,base,(str,),class,DivideByZero,static,int,Method(,int,a,int,b),if,(a 0),throw,new,MyException,(,被除数不能小于零,);,if,(b=0),throw,new,DivideByZeroException,(,除数不能等于零,);,int,c=a/b;,return,c;,static,void,Main(),int,a=3,b=0;,int,c=,Method(a,b,);,8.3,异常的捕捉及处理,异常引发后。如果程序中没有定义相应的处理代码,系统将按例,8-1,所示默认方式处理。实际编程时,为了确保异常能被正确地捕捉并成立,需要在程序中加入相应的异常处理代码。,8.3.1,异常处理的基本语法,8.3.2,捕捉并处理所有异常,8.3.1,异常处理的基本语法,异常处理需要使用,try-catch,结构,语法形式为:,try,可能引发异常的程序代码,catch(Type1 id1),对,Type1,类异常进行处理的异常处理程序,catch(Type2 id2),对,Type2,类异常进行处理的异常处理程序,catch(TypeN,idN,),对,TypeN,类异常进行处理的异常处理程序,try,块中放可能引发异常的程序代码,catc,块放异常处理程序代码,8.3.1,异常处理的基本语法(续),catch,块中的异常参数类型通常被称作“异常筛选器”。如果某个,catch,块中的异常处理程序中没有使用该参数变量,可以只指定异常类型,没有必要同时给出参数变量。,例:,try,int,i=,int.Parse(aaaa,);,catch(FormatException,),System.Console.WriteLine,(,不能转换,);,8.3.1,异常处理的基本语法(续),C#,程序运行时,如果引发了异常,程序将中断正常运行,系统检查引发异常的语句以确定它是否在,try,块中。如果是,则从与,try,关联的第一个,catch,块开始,按照,catch,块中的异常参数类型找出最先与之匹配的,catch,块,执行其中异常处理代码。然后执行所有,catch,块后的语句。,8.3.1,异常处理的基本语法(续),例,8-2,异常处理,SumUpException,10,SumUpException,SumUpException,3.6,SumUpException,0,源代码,运 行,运 行,运 行,运 行,例,8-2,异常处理,using,System;,public,class,SumUpException,public,static,int,Main(,String,args,),if,(args.Length,!=1),Console,.WriteLine,(,命令行形式应为,a:SumUpException,N(N,为正整数,),);,return,1;,例,8-2,异常处理(续),try,int,n=,Int32,.Parse(args0);,/,可能引发,FormatException,异常,if,(n,1),throw,new,ArgumentOutOfRangeException,(,args,);,int,sum=0;,int,i=1;,while,(i,=n),sum=,sum+i,;,i+;,Console,.WriteLine(,sum,=0,sum);,例,8-2,异常处理(续),catch,(,FormatException,),Console,.WriteLine,(,命令行参数,N,应为整数,);,catch,(,ArgumentOutOfRangeException,e),Console,.WriteLine(e,);,return,0;,例,8-2,运行结果,命令行为:,SumUpException,10,SumUpException,异常处理不在,catch,块中,SumUpException,3.6,引发FormatException异常,SumUpException,0,引发,ArgumentOutOfRangeException,异常,8.3.1,异常处理的基本语法(续),例,8-3,异常处理过程,Divide -10 2,Divide 10 2,Divide 10,Divide 10 0,源代码,运 行,运 行,运 行,运 行,例,8-3,异常处理过程,using,System;,public,class,Divide,static,int,Method(,int,a,int,b),if,(a,0),throw,new,ArgumentOutOfRangeException,(,a,a,不能小于零,!,);,if,(b,0),throw,new,ArgumentOutOfRangeException,(,b,b,不能小于零,!,);,return,a/b;,public,static,int,Main(,String,args,),if,(args.Length,!=2),Console,.WriteLine,(,命令行形式应为,:Divide A B(A,、,B,为正整数,),);,return,1;,例,8-3,异常处理过程(续),try,int,a=,Int32,.Parse(args0);,int,b=,Int32,.Parse(args1);,Console,.WriteLine(,0/1=2,a,b,Method(a,b);,catch,(,ArgumentOutOfRangeException,e),Console,.WriteLine(e,);,return,0;,例,8-3,运行,命令行为:,Divide -10 2,引发,ArgumentOutOfRangeException,异常,Divide 10 2,Divide 10,异常处理不在,catch,块中,Divide 10 0,未经处理的,DivideByZeroException,异常,8.3.2,捕捉并处理所有异常,为保证,try-catch,结构中的,catch,块可以捕捉并处理所有的异常,可以将其中的一个,catch,块的异常参数类型定义为,Exception,类。,应将较具体或常产生的异常的,catch,块放在前面,而可以与多种异常相匹配的,catch,块放在较后的位置。事实上,如果将基础类异常放在其派生类之前处理,编译器会报告错误。,例,8-4,捕捉并处理所有异常,例,8-4,捕捉并处理所有异常,using,System;,public,class,Divide1,static,int,Method(,int,a,int,b),if,(a,0),throw,new,ArgumentOutOfRangeException,(,a,a,不能小于零,!,);,if,(b,0),throw,new,ArgumentOutOfRangeException,(,b,b,不能小于零,!,);,return,a/b;,public,static,int,Main(,String,args,),if,(args.Length,!=2),Console,.WriteLine,(,命令行形式应为,a:Divide,A B(A,、,B,为正整数,),);,return,1;,例,8-4,捕捉并处理所有异常(续),try,int,a=,Int32,.Parse(args0);,int,b=,Int32,.Parse(args1);,Console,.WriteLine(,0/1=2,a,b,Method(a,b);,catch,(,ArgumentOutOfRangeException,e1),Console,.WriteLine(e1);,catch,(,Exception,e2),Console,.WriteLine(e2);,return,0;,例,8-4,运行,命令行为:,Divide -10 2,引发,ArgumentOutOfRangeException,异常,Divide 10 2,Divide 10,异常处理不在,catch,块中,Divide 10 0,引发,DivideByZeroException,异常,8.3.2,捕捉并处理所有异常(续),对,Exception,类型的异常,如果,catch,块中不使用参数变量,可以不列出异常类型,例:,try,int,i=,int.Parse(aaaa,);,catch,/,等价于,catch(Exception,),System.Console.WriteLine,(,不能转换,);,8.4 finally,语句,如果希望某些语句不管是否发生异常都被执行,可以利用关键字,finally,在,try-catch,块后指定这些语句。语法形式为:,try,可能引发异常的程序代码,catch(Type1 id1),对,Type1,类异常进行处理的异常处理程序,catch(Type2 id2),对,Type2,类异常进行处理的异常处理程序,catch(TypeN,idN,),对,TypeN,类异常进行处理的异常处理程序,finally,每次都执行的代码,8.4 finally,语句(续),每个,try,块后至少紧接一个,catch,块或,finally,语句块。,无论,try,块内是否引发异常,相应的,finally,语句块都被执行。,例,8-5 finally,语句的执行,源代码,运 行,例,8-5 finally,语句的执行,using,System;,public,class,FinallyException,public,static,void,Main(),int,array=,new,int,2;,for,(,int,i=-1;i,array.Length;i,+),/i=-1,时引发异常,try,arrayi,=i;,Console,.WriteLine,(,没有引发异常,);,例,8-5 finally,语句的执行(续),catch,Console,.WriteLine,(,引发了异常,);,finally,Console,.WriteLine,(,运行,finally,语句块,);,8.5,关键字,checked,和,unchecked,每种数值类型都有一定的取值范围。运算时,如果运算结果超出目标类型的取值范围,就会发生溢出。如果表达式的类型是,float,或,double,型,溢出时将相应地返回一个,PositiveInFinity,或,NegativeInFinity,值;,如果表达式的类型是,decimal,型,常量表达式的算法溢出会导致编译错误,而非常量表达式的算法溢出会引发,OverflowException,异常。,8.5,关键字,checked,和,unchecked,(续),例:,decimal d=,Decimal.MaxValue,;,Console.WriteLine(d,*2);,/,引发异常,decimal d1=,Decimal.MaxValue,*2;,/,编译错误,8.5,关键字,checked,和,unchecked,(续),默认情况下,整数类型表达式的值如果超出了目标类型的取值范围,则常数表达式将导致编译错误,而非常数表达式在已检查的上下文中执行时计算并将引发,OverflowException,异常。,当整数类型的表达式在未检查的上下文中执行时,算法溢出被忽略并且结果被截断,而不是被认为是一个错误。,8.5,关键字,checked,和,unchecked,(续),一般情况下,,C#,语句执行的默认上下文为未检查的上下文(整数类型常量表达式的默认上下文总是已检查的上下文),可以使用关键字,checked,指定已检查的上下文。不过,如果通过编译器选项或环境配置在全局范围内启动了溢出检查(此时,默认上下文为已检查的上下文),则可以使用,unchecked,关键字来指定未检查的上下文。在未检查的上下文中,溢出检查被取消。,8.5,关键字,checked,和,unchecked,(续),下列操作受溢出检查的影响:,表达式在整数类型上使用下列预定义运算符:,+-,(一元),+-*/,整数类型间的显式数值类型转换。,例,8-6,溢出检查,源代码,运 行,例,8-6,溢出检查,using,System;,class,TestOverflow,static,void,Main(),int,x=,Int32,.MaxValue;,int,y=0;,例,8-6,溢出检查(续),try,y=,unchecked,(x,+1);,Console,.WriteLine(,Unchecked,output value:0,y);,y=,checked,(x,+1);,Console,.WriteLine(,Checked,output value:0,y);,catch,(,System.,OverflowException,e),Console,.WriteLine(e,);,8.5,关键字,checked,和,unchecked,(续),关键字,checked,和,unchecked,可以作用于语句块。语句块中所有的算术运算和转换都会被相应处理。例:,unchecked,int,val,=Int32.MaxValue+1;,8.5,关键字,checked,和,unchecked,(续),如果程序中的某些语句没有显式使用关键字,checked,或,unchecked,指定上下文,这些语句就在默认的上下文中执行。常量表达式的默认上下文总是已检查的上下文。不过,在使用,csc,编译器进行编译时,可以使用,/checked,编译器选项为非常量表达式指定默认的上下文。,8.5,关键字,checked,和,unchecked,(续),/,Test.cs,using System;,class Test,static void Main(),int,d=Int32.MaxValue;,d+;,8.5,关键字,checked,和,unchecked,(续),上述程序使用下述两个编译命令之一进行编译后,语句执行的默认上下文为已检查的上下文,因此,运行时将会引发异常:,csc,/checked,Test.cs,csc,/checked+,Test.cs,关键字,checked,和,unchecked,(续),使用下述编译命令进行编译,语句执行的默认上下文为未检查的上下文,因此,运行时不会引发异常:,csc,/checked-,Test.cs,关键字,checked,和,unchecked,(续),checked,或,unchecked,关键字范围内的整数算法语句不受,/checked,选项的影响。,如果不在,checked,或,unchecked,关键字范围内的整数算法语句产生的值超出数据类型范围,并且编译中使用了,/checked+(/checked),,则该语句将在运行时导致异常。如果编译中使用的是,/checked-,,则该语句在运行时不会导致异常。,该选项的默认值为,/checked-.,在,Visual Studio,开发环境中设置此编译器选项,打开项目的“属性”页(项目,“,项目名”属性),单击“生成”属性页,单击“高级”按钮。,修改“检查算法上溢,/,下溢”属性。,点击“确定”按钮,8.6,习 题,1.,什么是异常?所有异常类型都派生于什么类?程序中自定义异常类应该派生于什么类?,异常是指程序运行过程中出现的非正常事件。是程序错误的一种。,异常类型都派生于,Exception,类,自定义异常类应该派生于,System.ApplicationException,类。,2.,写出异常类中的两个常用属性,并指出它们的作用分别是什么?,异常类都定义有下述属性:,Message /,获取描述当前异常的消息,StackTrace,/,获取当前异常发生时调用堆栈上的状态,作业,3,、编写一个程序,引发一个,IndexOutOfRangeException,异常,并捕捉处理。,5,、声明一个对象引用并初始化为,null,,在程序中试着通过这个引用调用某个方法。使用,try-catch,结构捕捉异常,并加入,finally,语句,在其中输出信息,证明它确实被执行了。,
展开阅读全文