1、第一部分 Microsoft.NET 框架基本原理第二部分 类型与通用语言运行时第三部分 类型设计第四部分 基本类型第五部分 类型管理,第五部分 类型管理异常自动内存管理,第18章 异常,18.1 异常处理的概念,看以下代码:class Program static void Main(string args)int values=new int 10;for(int i=1;i=10;i+)Console.WriteLine(valuesi);Console.ReadKey();,18.1 异常处理的概念,看以下代码:class Program static void Main(string
2、 args)int values=new int 10;for(int i=1;i=10;i+)Console.WriteLine(valuesi);Console.ReadKey();,C#中数组下标从0开始,因而此代码在运行时将会发生一个“数组访问越界”错误。,类似于这种在程序中隐藏的错误,被称为“异常(Exception)”,它表明程序执行期间出现了一个非法的运行状况,期望程序进行的某项操作没能完成。注意,异常是在程序运行时间出现的,不是在编译期间出现的,编译器在编译时发现的错误是语法错误,不能称之为异常。.NET Framework 提供了多个异常类,在编程中常用的有以下几个:,异常处
3、理的目的是根据不同的异常情况提供不同的处置方法,使程序更稳定、更安全。异常处理的主要用途是提供准确的错误消息,解释失败的原因、位置和错误类型等,同时提供一定的恢复能力,尽可能地降低出错的机率。,使用try、catch 和 finally 处理异常的结构如下:try/可能引发异常的语句-try语句块(1)catch(Exception e)/对异常进行处理的语句-catch语句块(2)finally/“打扫战场”的语句-finally语句块(3),18.2 编程实现异常处理,18.2.1 try、catch 和 finally,异常处理机制将代码分成3大块。第(1)块是正常执行程序功能的语句块,
4、其中有可能在运行时引发错误。第(2)块在程序正常运行时不会执行,仅当有异常出现时转到此块执行。第(3)块不管程序执行时有无异常出现都会执行。当程序正常运行时,程序的执行流程为:第(1)块 第(3)块 当第(1)块中有代码引发了一个异常时,程序的执行流程为:第(1)块 第(2)块 第(3)块可以有多个catch语句块,每个代码块捕获一种异常(由catch后的参数类型决定,称为“异常筛选器(Exception Filter)”)。.NET Framework中使用catch语句只能捕获Exception类及其子类的对象。当一个异常被引发后,如果应用程序没有提供合适的异常处理代码,应用程序进程将会被
5、CLR强制中止。,异常处理机制将代码分成3大块。第(1)块是正常执行程序功能的语句块,其中有可能在运行时引发错误。第(2)块在程序正常运行时不会执行,仅当有异常出现时转到此块执行。第(3)块不管程序执行时有无异常出现都会执行。当程序正常运行时,程序的执行流程为:第(1)块 第(3)块 当第(1)块中有代码引发了一个异常时,程序的执行流程为:第(1)块 第(2)块 第(3)块可以有多个catch语句块,每个代码块捕获一种异常(由catch后的参数类型决定,称为“异常筛选器(Exception Filter)”)。.NET Framework中使用catch语句只能捕获Exception类及其子类
6、的对象。当一个异常被引发后,如果应用程序没有提供合适的异常处理代码,应用程序进程将会被CLR强制中止。,异常处理机制将代码分成3大块。第(1)块是正常执行程序功能的语句块,其中有可能在运行时引发错误。第(2)块在程序正常运行时不会执行,仅当有异常出现时转到此块执行。第(3)块不管程序执行时有无异常出现都会执行。当程序正常运行时,程序的执行流程为:第(1)块 第(3)块 当第(1)块中有代码引发了一个异常时,程序的执行流程为:第(1)块 第(2)块 第(3)块可以有多个catch语句块,每个代码块捕获一种异常(由catch后的参数类型决定,称为“异常筛选器(Exception Filter)”)
7、。.NET Framework中使用catch语句只能捕获Exception类及其子类的对象。当一个异常被引发后,如果应用程序没有提供合适的异常处理代码,应用程序进程将会被CLR强制中止。,注意:指定由逗号分开的catch参数表是语法错误,catch只能有一个参数,即一条catch语句只能捕获此参数限定的那种类型的异常。另外,在某个try块后有两个不同的catch块捕获两个相同类型的异常也是语法错误。finally语句块是可选的,主要用于解决资源泄露问题,它位于catch语句块之后,CLR保证它们一定执行。注意:finally语句块中也可能发生异常,如果这种情况发生,先前的异常被放弃。程序中也
8、可使用 throw 关键字主动地抛出一个异常:throw new Exception(“我的新异常对象”);,上节中引发“数组访问越界”错误的代码可以用异常处理机制重写如下:class Program static void Main(string args)int values=new int 10;try for(int i=1;i=10;i+)Console.WriteLine(valuesi);,catch(IndexOutOfRangeException e)Console.WriteLine(“在输出values数组值时发生数组越界错误”);Console.WriteLine(“异
9、常种类:”+e.GetType().Name);Console.WriteLine(“系统给出的出错信息:”+e.Message);Console.WriteLine(“系统调用堆栈信息:”+e.StackTrace);Console.WriteLine(“引发此错误的方法:”+e.TargetSite);Console.ReadKey();,当程序运行时,异常提示信息如下:在输出values数组值时发生数组越界错误 异常种类:IndexOutOfRangeException 系统给出的出错信息:索引超出了数组界限 系统调用堆栈信息:在 OnlyTest.Program.Main(String
10、 args)位置 C:OnlyTestProgram.cs:行号 11 引发此错误的方法:Void Main(System.String),.NET Framework异常处理的核心是Exception类,它是所有可捕获异常类的基类,程序发生异常时,CLR 会创建一个相应种类的异常对象来表示该异常。Exception 对象 e 的3个重要属性。,.NET Framework 实现的异常处理具有以下特点:处理异常时不用考虑生成异常的语言或处理异常的语言。异常处,理时不要求任何特定的语言语法,而是允许每种语言定义自己的语法。允许跨进程甚至跨计算机边界引发异常。为达以上目的,CLR为每个正在运行的程
11、序创建了一个异常信息表。在异常信息表中,程序中每个方法都有一个关联的异常处理信息数组。如果方法中有受到保护的语句块,则此方法相关联的异常处理信息数组中就记录了当异常发生时,CLR自动调用异常处理代码所需的相关信息。如果某方法中没有受保护块,则其对应的异常处理信息数组为空。提示:被 trycatch 包围的语句块称为受保护块。,18.2.2 CLR 结构化异常处理原理,当某一方法中发生异常时,CLR 在此方法对应的异常处理信息数组中搜索,以确定是哪一个受保护块引发的异常,以及应该由哪个catch块处理。(1)如果找到以上信息,CLR创建一个Exception对象(或其子类对象)来描述该异常。然后
12、,CLR执行处理该异常的catch语句块,如果有finally语句块,接着执行finally语句块。(2)如果在当前方法中没有找到相关信息,则CLR搜索当前方法的每一个调用方,在调用者的异常处理信息数组中搜索,直到最顶层的调用者。这个由底向上的搜索过程,其信息被记录在一个堆栈中,称为“异常堆栈”。(3)如果任何调用者都没有处理这种异常的代码,则CLR允许使用一个调试器来处理该异常。如果用户放弃调试,则CLR引发一个UnhandledException事件,而这时如果应用程序也没有编写响应UnhandledException事件的代码,则CLR会结束此进程。,public void SomeMe
13、thod()try/这里执行一些操作 catch(NullReferenceException e)/处理一个空引用异常 catch(InvalidCastException e)/处理一个无效转型异常 catch/在C#中,该筛选器会捕获任何异常/处理所有异常,首先创建一个自定义的异常类MyException。class MyException:Exception public MyException(String info):base(info)接着,编写代码实现以下的方法调用链,在SomeFunc()方法中引发一个Exception异常。Main()FuncInvoker()SomeFu
14、nc()具体代码如下:,异常的传播过程,static void Main(string args)FuncInvoker();static void FuncInvoker()SomeFunc();static void SomeFunc()throw new MyException(“主动引发的异常”);,异常的传播过程,可以在整个异常“传输链”中的任何一环“打断”整个异常传输,以避免进入调试阶段。修改 FuncInvoker 函数:static void FuncInvoker()try SomeFunc();catch(MyException e)Console.WriteLine(程序
15、中出现了异常);Console.WriteLine(其信息为:+e.Message);,如果最底层的SomeFunc()函数引发的不是MyException异常,而是其他类型的异常,则FuncInvoker方法中的trycatch块又不管用了,还是会引发CLR报告错误。解决方法:可以在FuncInvoker方法中再增加一个catch语句块,专门处理此种类型的异常。,由于程序中可以引发的异常种类很多,很难一一写代码处理,最保险的方法是在最顶层方法中捕获Exception异常。static void Main(string args)try FuncInvoker();catch(Exceptio
16、n e)Console.WriteLine(e.Message);,第19章 自动内存管理(垃圾收集),19.1 垃圾收集平台基本原理解析,访问一个资源所需要的几个步骤:1.调用中间语言(IL)中的 newobj 指令,为表示某个特定资源的类型实例分配一定的内存空间。2.初始化上一步所得的内存,设置资源的初始状态,从而使其可以为程序所用。一个类型的实例构造器负责做这样的初始化工作。3.通过访问类型成员来使用资源,这根据需要会有一些反复。4.销毁资源状态,执行清理工作。5.释放内存。这一步由垃圾收集器全权负责。,以上模式却是导致许多编程错误的主要原因之一。释放无用的内存、试图访问已经被释放的内存,这两类bug发生的时间和次序都难以预料;这两类bug的直接后果是资源泄露(内存消耗)和对象损毁(状态不稳定)。正确无误的资源管理通常是一件比较困难和单调的工作,它们极大地分 散开发人员解决实际问题的注意力。垃圾收集(garbage collection)机 制能够简化这种容易遗漏的内存管理任务。大多数类型表示的资源并不需要任何特殊的清理操作。对于一个表示(或者说封装)着非托管(操作系统)资源的类
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1