• 博客园logo
  • 会员
  • 周边
  • 新闻
  • 博问
  • 闪存
  • 众包
  • 赞助商
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
口口念念
博客园    首页    新随笔    联系   管理    订阅  订阅
读书笔记之结构化异常处理

 


一、内容摘要

结构化异常处理是一种操作系统提供的机制,用来优化程序的结构,提供更加健壮的程序执行环境。异常是指需要特殊处理的例外情况,包括运行时发生的错误,如除数为零、存储空间不足等。异常处理提供了一种标准的方法以处理错误,发现可预知及不可预知的问题,及允许开发者识别、查出和修改错漏之处。

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块中去执行异常处理。



 

posted on 2012-02-12 22:43  口口念念  阅读(299)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2026
浙公网安备 33010602011771号 浙ICP备2021040463号-3