27.异常
一、异常概述
系统在运行程序的时候,发生的严重错误。为了预防系统崩溃,给用户一个良好的反馈,这时就需要引入异常处理。
在C# 程序中,引发异常共有以下两种发生:
(1)使用显式 throw 语句来引发异常。在此情况下,控制权将无条件转到处理异常的部分代码;
(2)使用语句或表达式在执行过程中激发了某个异常的条件,使得操作无法正常结束,从而引发。
注:
1、对于引发什么异常不确定时,可以定义多个 catch 语句,精确捕捉异常(尽量先捕捉小的异常)。因为 Exception 类捕获异常时是从根异常开始逐层往上捕捉子异常,比较复杂,所以提倡精确捕捉;
2、处理异常语句虽然能使发生异常的语句执行,但处理异常会大大降低性能,不能将他用在控制正常程序流程中。
二、处理异常的语句:
将可能出现异常的代码放入 try 语句中,如果 try 中代码本次运行无异常,则正常输出(不运行catch语句);如果 try 中代码本次运行有异常,则跳过异常运行catch语句。例如设计一个除法程序,若用户输入尝试除以零,则 try 语句块中则出现异常,若用户不除零则正常执行try中代码。
1、try...catch //捕获异常
2、try...finally //清除异常
3、try...catch...finally //处理所有异常。“finally{···}”无论是否发生异常都会执行。适合做网络连接相关的
注:必须至少有一个catch块.
例1:普通捕捉异常
1 class Program 2 { 3 public void ExceptionTest() 4 { 5 int _intNum1 = 10; 6 int _intNum2 = 0; 7 int _intResult = 0; 8 //异常处理 9 try 10 { 11 //出现问题的代码 12 _intResult = _intNum1 / _intNum2; 13 } 14 catch (Exception e) //跳过出现问题的代码执行下面的语句 15 { 16 Console.WriteLine("发生了严重问题,请联系客服处理!"+e.Message); 17 } 18 Console.WriteLine("_intResult = {0}",_intResult); 19 } 20 static void Main(string[] args) 21 { 22 Program obj = new Program(); 23 obj.ExceptionTest(); 24 Console.ReadKey(); 25 } 26 }
例2:添加多个catch块精确捕捉异常
1 class Program 2 { 3 public void ExceptionTest() 4 { 5 int _intNum1 = 10; 6 int _intNum2 = 0; 7 int _intResult = 0; 8 9 //异常处理 10 try 11 { 12 //出现问题的代码 13 _intResult = _intNum1 / _intNum2; 14 } 15 catch(DivideByZeroException e) //当我们认为该异常是除零引发,但又不确定 16 //所以为了防止异常引发系统崩溃,则加一个catch(Exception)块,从根异常开始捕获 17 { 18 Console.WriteLine("发生除零异常,请联系客服处理:"+e.Message); 19 } 20 catch (Exception e1) 21 { 22 Console.WriteLine("发生了严重问题,请联系客服处理!" + e1.Message); 23 } 24 Console.WriteLine("_intResult = {0}",_intResult); 25 } 26 static void Main(string[] args) 27 { 28 Program obj = new Program(); 29 obj.ExceptionTest(); 30 Console.ReadKey(); 31 } 32 }
三、 Exception类
1. InvalidCastException 当从基类型或接口到派生类型的显式转换在运行失败时,就会引发此异常;
2. ArrayTypeMismatchException 当存储一个数组时,如果由于被存储的元素的实际类型与数组的实际类型不兼容而导致存储失败,就会引发此异常 ;
3. ArithmeticException 算术运算期间异常发生的类型;
4. DivideByZeroException 试图除以零引发;
5. OverflowException 溢出时引发;
6. FormatException 参数格式无效时引发;
7. Exception 所有异常类的基类;
8. SystemException 运行时产生的所有错误的基类;
9. IndexOutOfRangeException 当一个数组的下标超出范围时引发;
10. NullReferenceException 当一个空对象被引用时引发;
11. ArgumentException 所有参数异常的基类。
四、Exception类的相关属性
(1)Message : 描述引发当前异常的信息;
(2)Source : 输出引发当前异常的程序(或者说项目)或对象名称;
(3)StackTrace : 输出引发当前异常的具体位置(具体到第几行代码);
(4)InnerException : 表示引发当前异常的内部异常对象。
五、 自定义异常
1、使用关键字“throw”自动引发异常
1 /// <summary> 2 /// 自定义异常 3 /// </summary> 4 /// <param name="intSaleNumber">销售的数量</param> 5 public void TestThrowException(int intSaleNumber) 6 { 7 if (intSaleNumber<0) 8 { 9 //使用关键字“throw”自动引发异常。为什么不直接 Console.WriteLine("销售额不能为负数!"),
//因为如果不使用throw抛异常,在 try 中这段代码正常执行而不会执行 catch 语句块。 10 throw new Exception("销售额不能为负数!"); 11 } 12 else 13 { 14 //计算销售额公式 15 } 16 } 17 public void Test() 18 { 19 try 20 { 21 TestThrowException(-10); //将会引发异常 22 } 23 catch (Exception e) 24 { 25 Console.WriteLine("发生错误:"+e.Message); 26 } 27 }
六、自定义异常类
1 namespace ProgramTest2 2 { 3 /// <summary> 4 /// 定义自己的“输入非法异常”类 5 /// </summary> 6 /// 指示一个类可以序列化。序列化在数据传输时用到 7 [Serializable] 8 class InvalidInputException : ApplicationException 9 { 10 //构造函数 11 public InvalidInputException(string strException) : base(strException) 12 { } 13 } 14 15 class Program 16 { 17 /// <summary> 18 /// 自定义异常:throw引发 19 /// </summary> 20 /// <param name="intSaleNumber">销售的数量</param> 21 public void TestThrowException(int intSaleNumber) 22 { 23 if (intSaleNumber < 0) 24 { 25 //使用自己定义的“非法输入异常”类 26 throw new InvalidInputException("销售额不能为负数!"); 27 } 28 else 29 { 30 //计算销售额公式 31 } 32 } 33 public void Test() 34 { 35 try 36 { 37 TestThrowException(-10); //将会引发异常 38 } 39 catch (InvalidInputException e1) 40 { 41 Console.WriteLine("引用自己定义的“输入非法异常”。信息输出为:" + e1.Message); 42 } 43 catch (Exception e) 44 { 45 Console.WriteLine("发生错误:" + e.Message); 46 } 47 } 48 static void Main(string[] args) 49 { 50 Program obj = new Program(); 51 obj.Test(); 52 Console.ReadKey(); 53 } 54 } 55 }