一、try-catch-finally的组合
举个极其简单的例子。一个长度4的字符串数组,但在调用时,循环执行了5次。这就导致了数组指针溢出的异常。
string[] strTest = new string[4] { "I", "Love", "You", "!" };
try
{
for (int i = 0; i < 5; i++) {
Console.WriteLine(strTest[i]);
}
}
catch
{
Console.WriteLine("出现异常");
}
finally {
Console.WriteLine("无论程序执行try还是catch,我都会出现的");
}
Console.ReadKey();
执行结果:
I
Love
You
!
出现异常
无论程序执行try还是catch,我都会出现的
由此可见,C#在程序执行过程中,会依次执行代码程序,在遇到异常块时,会触发异常。并跳出try块。哪怕这条异常后面的代码是没有问题的,他也不会执行了。
而finally则是无论执行了try还是catch他都会执行。那么我们可以将程序最后要做的并且安全系数很高的事情放到finally里面去做。比如垃圾回收,变量清空等等。
二、throw
throw 的功能,在我个人理解来看,就是把“球”踢给别人。而且通常是从下向上踢。他本身不处理异常,而是通知调用它的层:“我身上有异常的,你发现了就帮我处理一下吧”。
举个例子说,通常在实际应用中,我们建立了一个类库。而类库本身不需要引用System.Windows.Form。而需求中要求将所有的异常通过MessageBox来通知给用户,这时我们就可以在类库的方法中将异常抛出给调用它的主程序(如Form1)去处理。
我们用控制台做个例子,窗体程序其实和他几乎没区别的。
先定义一个方法
public static void JudgeNumber(int a) {
if (a==0) {
Exception e = new Exception();
throw new Exception("我们不需要0");
}
}
这里,当传参为0时,其实是不会触发系统异常的。但我们需要他报出异常。换句话说,这时根据自己的要求自定义的异常
在主程序中调用方法JudgeNumber。
try
{
JudgeNumber(0);
}
catch(Exception e) {
Console.WriteLine(e.Message.ToString());
}
Console.ReadKey();
三、有时我们需要知道,我们到底触发了什么异常。常遇到的异常通常如下
ArgumentNullException //一个空参数传递给方法,该方法不能接受该参数
ArgumentOutOfRangeException //参数值超出范围
ArithmeticException // 出现算术上溢或者下溢
ArrayTypeMismatchException // 试图在数组中存储错误类型的对象
BadImageFormatException // 图形的格式错误
DivideByZeroException // 除零异常
DllNotFoundException // 找不到引用的DLL
FormatException // 参数格式错误
IndexOutOfRangeException // 数组索引超出范围
InvalidCastException // 使用无效的类
InvalidOperationException // 方法的调用时间错误
NotSupportedException // 调用的方法在类中没有实现
NullReferenceException // 试图使用一个未分配的引用
OutOfMemoryException // 内存空间不够
StackOverflowException // 堆栈溢出
说实话,我记不住。但公司最近规定,要求将触发异常的类型区分并反馈出来。那该怎么办呢?
其实非常简单。
我们可以调用 Exception的方法:GetType().Name 来完成它。
代码如下:
try
{
Division(4, 0);
}
catch(Exception e) {
Console.WriteLine("异常类型:" + e.GetType().Name);
Console.WriteLine("异常信息:"+e.Message);
}
Console.ReadKey();
public static int Division(int a,int b){
return a/b;
}
运行结果:
异常类型:DivideByZeroException
异常信息:试图除以零。