c#语言系列讲座(17) 异常处理

来源:互联网 发布:医药魔方数据库 编辑:程序博客网 时间:2024/05/10 04:50
异常处理

结构化异常处理是现代分布式环境下组件设计的一个必要的环节,.NET通用语言运行时从底层构造给予异常处理以坚实的支持。在C#中,异常对象被设计为封装了各种异常信息的类(System.Exception及其继承子类,和接口类似,它被推荐命名时加上后缀“Exception”,但这并非必须),“try-catch-finally”语句和异常对象一起为C#组件设计提供从异常侦测、异常捕捉和处理等一揽子服务。

我们将可能出现异常的语句放在try语句块内,这样,代码中出现的异常才可能被侦测到并传递给catch语句。catch语句可以带参数,也可以不带参数,catch语句所带参数类型只能为System.Exception及其继承子类。带参数的catch语句将只捕捉参数指定类型的异常,对于其他异常不予处理。不带参数的catch语句相当于参数为System.Exception类型的异常(即所有的异常),只不过不能获取异常变量。一个try语句块后面可以匹配多个catch语句,以捕捉不同的异常类型。这里必须注意的是多个catch语句的顺序,后面的catch语句中的参数类型不能是前面类型的子类,也不能和前面的参数类型相同。

如果catch语句的参数类型没有匹配try语句侦测到的异常类型,异常将在该语句的方法体内被抛出。如果调用该方法的方法没有相应的侦测和捕捉机制,那么异常继续被抛出,直到被捕捉,或者被抛出到应用程序的入口点Main函数,从而引起程序异常中断执行。这种异常抛出的机制对于在try语句之外出现的异常也同样适用——侦测到但没有捕捉到和没有侦测的效果一样!另外一点需要注意的是程序一旦发生异常,那么其后面的代码将不被执行!

但如果程序逻辑需要不管出现异常与否,都要执行某些任务紧急的代码(典型的如关闭打开的文件,网络端口等)怎么办呢?C#提供finally语句来解决这种情况。finally语句不能单独使用,它和try、catch有两种搭配情况: Try、catch、finally三者搭配构成try-catch-finally语句,在三者的搭配中,即使抛出了异常,finally语句也被执行; try语句还可以和finally语句搭配构成try-finally语句。try-finally语句侦测到异常后,只是简单地抛出,并没有捕捉。但在这种异常得到处理(被调用其方法的catch语句捕捉,或者到达Main函数入口点被执行环境中断)后,finally语句仍然执行。当然finally语句块只能有一个,这是不言自明的。

throw语句是用来抛出异常的,在代码设计中,遇到违背程序设计设定的条件,或异常的情况,我们常常要抛出特定的异常,这时候throw语句就很有用了,我们来看下面的例子:

using System;

public class MyException:ApplicationException {

public MyException (String message) : base (message) {}

public MyException (String message, Exception inner) : base(message,inner) {}

}

public class MyClass{

public static void ExMethod() {

throw new MyException(“Exception in ExMethod”); }

public static void MyMethod(){

try {ExMethod(); }

catch (Exception e) {

throw new MyException(“Exception in MyMethod”,e);}

}

}

public class Test {

public static void Main() {

try {

MyClass.MyMethod(); }

catch(Exception e) {

Console.WriteLine(e);

Console.WriteLine();

Console.WriteLine(e.GetBaseException());

}

}

}

程序输出:

MyException: Exception in MyMethod——> MyException: Exception in ExMethod

at MyClass.ExMethod()

at MyClass.MyMethod()

——End of inner exception stack trace——

at MyClass.MyMethod()

at Test.Main()

MyException: Exception in ExMethod

at MyClass.ExMethod()

at MyClass.MyMethod()

在上面的例子,我们设计了自己的异常类MyException,并在自己的设计类中简单地应用了这种异常类。测试程序中展示了它的处理,以及在多个方法调用中异常的追踪。其中e.GetBaseException()是调用System.Exception的GetBaseException()方法,获得引起异常e的最开始的那个异常,如果没有,将返回e自己。System.Exception的很多方法和属性为我们提供了很好的对异常的描述和追踪服务,它是我们应用异常、设计异常、认识异常的一个很好的起点。

Checked与Unchecked

对于因为整数类型参与算术操作和类型转换时产生的“溢出异常”——System.OverflowException,在某些算法来讲不算真正的“异常”,相反这种溢出常常为程序所用。C#通过引入checked和unchecked关键字来控制这种特殊情况的需求。它们都可以加于一个语句块前(如:checked{……}),或者一个算术表达式前(如:unchecked(x+y)),其中加checked标志的语句或表达式如果发生算术溢出,则抛出System.OverflowException类型的异常,而加unchecked标志的语句发生算术溢出时,则不抛出异常。下面是一个示例:

using System;

class Test{

static void Main() {

int num1=100000,num2=100000,

result=0;

checked{ try { result= num1 * num2;}

catch(System.Overflo2wException e){ Console.WriteLine(e); }

finally{ Console.WriteLine(result);}

}

unchecked{ try { result= num1 * num2;}

catch(System.OverflowException (e){ Console.WriteLine(e);}

finally{ Console.WriteLine(result);}

}

}

}

程序输出:

System.OverflowException: Arithmetic operation resulted in an overflow.

at Test.Main()

0

1410065408

可以看到同样的算术操作,用checked抛出了溢出异常,而unchecked只是将溢出的位丢弃而得到剩下的32位组成的十进制整数值。值得指出的是可以用“/checked”编译器选项指定整个文件的代码为checked语义,如果没有指定则默认为unchecked。如果同时在程序代码中指定checked或unchecked标志,又有了checked编译器选项,则除了标志为unchecked的代码外,其余的都有checked语义。
原创粉丝点击