一、内容摘要
结构化异常处理是一种操作系统提供的机制,用来优化程序的结构,提供更加健壮的程序执行环境。异常是指需要特殊处理的例外情况,包括运行时发生的错误,如除数为零、存储空间不足等。异常处理提供了一种标准的方法以处理错误,发现可预知及不可预知的问题,及允许开发者识别、查出和修改错漏之处。
C#中由try、throw、catch和finally关键字实现异常处理,而且提供了一个处理系统级和应用程序级错误状态的结构化的、统一的和类型安全的方法。此外,除了C#自己提供的异常类型,C#还支持自定义的异常类型。
二、学习目标
- 了解异常处理的基本知识
- 掌握如何抛出和捕获异常
- 理解嵌套try语句的使用
- 了解异常类
- 掌握内部异常
- 理解如何抛出预定义异常
- 如果创建和抛出自定义异常
- 理解finally语句块
三、主要内容
3.1 结构化异常处理的基本知识
错误、异常与调试的概念:
错误:程序错误按照发生机理可分为语法错误、语义错误与逻辑错误。
异常:程序执行时遇到的任何错误情况或意外行为。
调试:在应用程序中发现并排除错误的过程被称为调试。调试是帮助程序设计人员查找和排除代码错误的有效手段。
3.1.1 抛出和捕获异常
处理异常的主要机制:try/catch/finally
异常处理语句语法:
try { //可能产生异常的代码块 } catch (Exception e) { //对异常进行处理的代码块 } finally { //最终执行的代码块 }
实例1:
抛出和捕获异常
class Program
{
static void Main(string[] args)
{
int a = 0;
int b = 10;
int c = 0;
try
{
//当除数为0时抛出异常
a = b / c;
}
catch (Exception e)
{
Console.WriteLine("发生异常:{0}", e.Message);
}
finally
{
Console.ReadLine();
}
}
}
当除数为0时抛出异常,语句块catch (Exception e)成功捕获异常。
运行结果:

实例2:
一个try块可应对多个catch块
class myclass
{
static void ProcessString(string str)
{
if (str == null)
{
throw new ArgumentNullException();
}
}
static void Main(string[] args)
{
Console.WriteLine("输出结果为:");
try
{
string str = null;
ProcessString(str);
}
//注意:如果没有catch语句块,程序会异常终止,使用不带参数的catch子句,
//则可以捕获任意类型的异常。
catch (ArgumentNullException e)
{
Console.WriteLine("第一个异常:{0}", e.Message);
}
catch (Exception e)
{
Console.WriteLine("第二个异常:{0}", e.Message);
}
finally
{
Console.ReadLine();
}
}
}
本例通过两个catch语句块进行捕获异常,分别为ArgumentNullException异常和Exception异常。运行结果是:

3.1.2嵌套try语句
嵌套语法:
try
{
//代码块1
try
{
//代码块2
}
catch
{
//代码块3
}
finally
{
//最终代码
}
//代码块4
}
catch
{
//异常处理代码
}
finally
{
//最终代码
}
如果异常在外层的try块中抛出,异常由外层的catch捕获,并执行外层的finnally块;如果异常在内层try块(代码块2)中抛出,且有一个合适的内层catch块处理该异常,执行内层的finnally块之后,继续执行外层的try块(代码块4)。
如果异常在代码块3中抛出,就必须处理代码2抛出的异常。在catch块中抛出的另一个异常很正常。此时,异常的处理就跟在外层try块中抛出一样,程序会立即退出内层的catch块,执行内层的finnally块,在外层的catch块中搜索处理程序。同样,如果在内层的finnally块中抛出一个异常,搜索会在外层的catch块开始,执行最匹配的处理程序。
无论嵌套多少个try块,规则都一样。在每个块中,NET运行库顺序执行try块,查找合适的处理程序。在每个步骤中,退出catch块后,都会执行对应finnally块中的清理代码,但不执行finnally块外部的代码,直到找到合适的catch处理程序并执行为止。
进行try块嵌套的原因:
1. 修改异常的类型
2. 在不同的地方处理不同的异常
3.2 异常类
Exception异常类是所有异常的基类,是通过引发包含错误信息的异常来报告错误。
异常类的功能包括描述错误可读文本和发生异常时调用堆栈的状态。
3.2.1 基于类型筛选异常
实例3:
使用try/catch块捕获一个ArgumentNullException异常
class MyClass
{
public void test(string s)
{
if (s == null)
throw (new ArgumentNullException());
}
static void Main(string[] args)
{
MyClass x = new MyClass();
try
{
string s = null;
x.test(s);
}
catch (ArgumentNullException e)
{
Console.WriteLine("{0} First exception caught.", e);
}
catch (Exception e)
{
Console.WriteLine("{0} Exception caught.", e);
}
finally
{
Console.ReadLine();
}
}
}
当在test内部调用throw语句时,系统查找catch语句并显示错误消息。运行程序输出结果:

3.2.2 System .Exception:Exception类派生子类,是系统定义的各种异常。
System .Exception
class exception
{
static void Main(string[] args)
{
try
{
Exception myEx = new Exception("原始异常");
throw myEx;
}
catch (Exception ex)
{
Console.WriteLine("异常类型:{0}", ex.GetType().ToString());
Console.WriteLine("异常信息:{0}", ex.Message);
Console.WriteLine("堆栈跟踪:{0}", ex.StackTrace);
Console.WriteLine("应用程序名称:{0}", ex.Source);
}
finally
{
Console.ReadLine();
}
}
}
运行程序,输出结果:

3.2.3 预定义异常(内部异常)
3.2.4 抛出预定义异常——实例5:
抛出预定义异常
public class Person
{
public Person()
{ }
private int mintAge;
public int Value;
public int Age
{
get
{
Age = mintAge;
return Age;
}
set
{
if (Value > 10)
mintAge = Value;
else
throw new ArgumentException("发生异常,年龄小于10");
}
}
}
class class1
{
static void Main(string[] args)
{
Person p = new Person();
try
{
p.Age = 9;
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
finally
{
Console.ReadLine();
}
}
}
输出结果:

3.3自定义异常——实例6:
自定义异常
class numException : ApplicationException
{
public void printError()
{
Console.WriteLine("输入的是数字小于1或者大于9,请重新输入!!");
}
}
class CustomException
{
static void Main(string[] args)
{
string num;
do
{
Console.WriteLine("请输入一个数字,输入“exit”退出程序");
num = Console.ReadLine();
System.Text.RegularExpressions.Regex rx = new System.Text.RegularExpressions.Regex(@"^[1-9]$");
//使用正则表达式判断
try
{
if (rx.IsMatch(num))
{
for (int i = 0; i < 10; i++)
{
Console.WriteLine("{0}*{1}={2}", i, num, i * Convert.ToInt32(num));
}
}
else
{
//抛出错误异常
throw new numException();
}
//捕获异常
}
catch (numException ex)
{
ex.printError();
Console.WriteLine("异常类型:{0}", ex.GetType().ToString());
}
} while (!num.ToLower().Equals("exit"));
}
}
创建一个自定义异常类numException,该类没有具体实现,但继承了ApplicationException类,从而继承了Exception类,所以它拥有了Exception类中定义的属性和方法。
运行结果:

3.4 finally块
运行程序时,不管是否发生异常,finally块都会执行。
注意:finally块必须和try/catch一起使用,不管是否发生异常,finally块都将保证运行。
四、学习总结
如果我们的代码中访问了无效内存地址或者用0来除以一个数。那么就会导致异常的产生,该线程将被强制退出。
例如一段代码用到数学公式的运算,但是谁都不知道传给该函数的数就有可能导致用0来除以一个数这样的情况。那么用异常处理就可以帮助我们捕捉这种异常,然后跳转到我们的异常处理代码来进行修复。总而言之,我总结并掌握了异常处理的原理:任何被保护的代码段如果产生异常都会跳转到Exception块中去执行异常处理。

浙公网安备 33010602011771号