1、单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,可视化程序设计(,C#,),第五讲,内容提要,测试、调试与异常处理,attribute,(特性),编译预处理,unsafe,及指针,简介,应用程序开发,可以安装在客户端机器上,应用程序必须,无错误,无故障,可靠,稳健,查找和排除,错误或故障称为,调试,调试的必要性,计算机化的计费系统,在事物处理过程中,系统显示错误消息,系统发生故障,必须重新输入全部信息,在部署应用程序前必须先对其进行调试,错误类型,错误类型,语法错误,逻辑错误,运行时错误,语法错误、缺少括号等,在编译时确定,易于确定,错误的算法导致错误结
2、果、公式错误等,在执行过程中确定,难以调试,内存泄漏、以零作除数、异常,在运行时确定,难以调试,调试过程,调试器,观察程序的运行时行为,跟踪变量的值,确定语义错误的位置,查看寄存器的内容,查看内存空间,调试过程,暂停,可在代码中插入“断点”,以便在特,定行处暂停执行该代码,调试过程,右键单击所需代码行,以设置断点,选择“插入断点”,调试过程,选择“调试”,“,继续”以便继续执行程序,调试过程,.,NET,集成开发环境,Debug,模式,Release,模式,VS.NET,中的调试工具,“,局部变量”窗口,VS.NET,中的调试工具,“,监视”窗口,VS.NET,的调试工具,“,快速监视”对话框
3、VS.NET,中的调试工具,“,即时”窗口,VS.NET,中的调试工具,跨语言调试,调试使用,.NET,框架编写的应用程序以及,Win32,本机应用程序,加入正在运行的程序,调试多个程序,Visual Studio.NET,调试器的功能,异常,帐户,姓名,余额,300123,小王,300124,小黄,7,000,311320,小李,网上银行,某学生小王转帐,5000,到其朋友小李的帐面上,0,4500,数据库,系统将查询发送到数据库中,tranfer_money,(),sendquery,();,.,.,余额,4500,-5000,程序崩溃,拒绝交易,错误,系统出现故障,“,C#,”,中的异
4、常,C#,中的异常处理,.,INPUT Divisor,IF Divisor=0 THEN,Result=Divident/Divisor,.,代码片段,1,输入除数,结果,=,_,0,2,4,GOTO PREVIOUS LINE,触发异常处理程序,C#,中的异常处理,.,INPUT Divisor,Result=Divident/Divisor,.,代码片段,1,“,用户自定义”错误检查机制,难以检查输入的任何“特殊字符”,IF Divisor=0 THEN GOTO PREVIOUS LINE,IF Divisor 0 THEN PRINT,“,无效输入”,运行库,运行库应当提供,“错误检
5、查机制”,System.Exception,System.Exception,属性,Message,Source,StackTrace,InnerException,System.Exception,在,C#,程序中,引发异常共有以下两种方式,使用显式,throw,语句来引发异常。在此情况下,控制权将无条件转到处理异常的部分代码,使用语句或表达式在执行过程中激发了某个异常的条件,使得操作无法正常结束,从而引发异常,Try.Catch.Finally,try,和,catch,块,滤水器,filter_water,(),try,water();,catch,impurities.Show,();,
6、过滤水,杂质,/,程序代码,/,错误处理代码,try,/,程序代码,catch,(,IOException,ex,),/,错误处理代码,try,和,catch,块,try,/,程序代码,catch,(,IOException,ex,),/,错误处理代码,引发,I/O,设备异常,try,和,catch,块,try,/,程序代码,catch,(,ex,),/,错误处理代码,可处理系统中的,任何,一种,异常,System.Exception,try,和,catch,块,4-4,if(grade 150),throw new,InvalidNumberInput,(grade+“,不是合法的成
7、绩,”,);,throw,可用来引发自定义异常,“,InvalidNumberInput,”,使用,finally,try,/,程序代码,catch,/,错误处理代码,finally,/finally,代码,无论,有否异常该代码,都会执行,多重,catch,块,try,/,程序代码,catch,(,IOException,ex,),/,错误处理代码,catch,(,OutOfMemoryException,ex,),/,错误处理代码,用于捕捉两种异常的,“,catch,”,块,多重,catch,块,public class,MyException,:,System.ApplicationExc
8、eption,public,MyException(string,message):base(message,),try,int,c=a/b;,catch(MyExeption,ex),Console.WriteLine(ex.Message,);,.,.,if(b,=0),throw new,MyException,(“,除数不能为零,);,示例,-,建立自定义异常,using System;,public class,EmailCheckException:ApplicationException,private string _,mes,;,/,重写构造函数,public,EmailCh
9、eckException():base,(),_,mes,=null;,public,EmailCheckException(string,message):base,(),_,mes,=,message.ToString,();,public,EmailCheckException(string,message,Exception,myNew):base(message,myNew,),_,mes,=,message.ToString,();,/Message,属性的重载,public override string Message,get,return,格式错误,;,示例,-throw,自
10、定义异常,private,bool,InfoSave,(string name,string email),string,subStrings,=,email.Split,();,/,如果输入的,Email,不是被“,”,字符分割成两段,则抛出,Email,错误异常,if(subStrings.Length,!=2),throw new,EmailCheck,Exception,();,else,int,index=subStrings1.IndexOf(.);,/,查找被“,”,字符分成的两段的后一段中“,.”,字符的位置,没有“,.”/,或者“,.”,字符是第一个字符,则抛出,EmailE
11、rrorException,异常,if(index,=0),throw new,EmailCheck,Exception,();,/,如果“,.”,字符是最后一个字符,抛出,EmailErrorException,异常,if(subStrings1subStrings1.Length-1=.),throw new,EmailCheck,Exception,();,return true;,示例,-Catch,自定义异常,private void,Submit_Click(object,sender,System.EventArgs,e),if(textName.Text.Length,=0&,
12、textEmail.Text.Length,=0),MessageBox.Show,(,请填写正确的信息!,填写提示,MessageBoxButtons.OK,MessageBoxIcon.Information,);,return;,try,InfoSave,(,textName.Text,textEmail.Text,);,catch(EmailCheckException,err),MessageBox.Show(err.Message,邮件格式错误,System.Windows.Forms.MessageBoxButtons.OK,MessageBoxIcon.Information,
13、);,return;,MessageBox.Show,(“,发送成功。,成功,MessageBoxButtons.OK,MessageBoxIcon.Information,);,调试、测试、异常处理总结,调试是搜寻和消除应用程序中的错误的过程,语法错误表示编译器无法理解代码,调试模式可用来重复编译和排除应用程序中的错误,直至能够成功运行,“局部变量”窗口允许用户监控当前程序中所有变量的值,单元测试和集成测试是测试大型应用程序的常用技术,当应用程序遇到运行时错误时,就会引发异常,C#,中的所有异常都派生自,Exception,类,特性,Serializable,abstract class F
14、eedBase,标识这个类是可序列化的,可序列化就是这个类的一个,特性,描述性关键字,对程序中的元素如:类、字段、方法、属性,命名时以,Attribute,结尾,:,SerializableAttribute,使用时省略,Attribute,public sealed class,SerializableAttribute,特性其实是一个类,class Program,Obsolete(,不要使用旧的方法,请使用新的方法,true),static void Old(),static void New(),public static void Main(),Old();,使用序列化,fileSt
15、ream=new FileStream(profile.bin,FileMode.Create);,BinaryFormatter bf=new BinaryFormatter();,bf.Serialize(fileStream,Profile);,Serializable,abstract class FeedBase,要存储的对象标记为可序列化,包括他的父类和属性的类,使用二进制方式存储对象,二进制格式化器,将对象以二进制方式格式化为流,Serialize(Stream,serializationStream,Object graph),流,对象,Serialize,的用法,:,序列化的
16、过程,格式化程序,对象可否序列化,子类成员,可否序列化,将对象格式化,写入存储介质,异常退出,序列化对象中的子类成员,Y,Y,N,N,反序列化,把,Profile,对象存储成文件,怎么取出来呢?,读取,反序列化则是从特定存储介质中的数据重新构建对象的过程,存储,介质,Profile,对象,界面语言,:,英语,RssFeed,对象,代理服务器,数据转换为对象,使用反序列化,将序列化好的,Profile,数据反序列化为对象,fileStream=new FileStream(profile.bin,FileMode.Open);,BinaryFormatter bf=new BinaryForma
17、tter();,Profile=(Profile)bf.Deserialize(fileStream);,将指定流反序列化,类型转换,public Object,Deserialize,(Stream,serializationStream,),Deserialize,的用法,:,流,对象,需要类型转换,序列化与反序列化,几个重要的类,SerializableAttribute,Formatter,可以将对象从一个应用程序发送到另一个应用程序中,使用场合,Web Service,分布式应用,反射,可以,ILDasm,反编译工具浏览一个,dll,和,exe,的构成,这种机制叫做,反射(,Refl
18、ection,),应用程序或,dll,类的属性,类的方法,应用程序信息,用于在运行时通过编程方式获得类型信息,反射,现场演示,通过代码演示获取,dll,的版本号,using,System.Reflection,;,class Program,static void,Main(string,args,),string version=,Assembly.LoadFile(D:MyNewsReader.exe,),.,GetName().Version.ToString,();,Console.WriteLine(version,);,引入命名空间,反射,C#,的预处理指令,预处理指令是,C#,编
19、译器在词法分析阶段读取的语句。这些语句可以指示编译器包含或不包含某些代码,甚至可以根据预处理指令的值终止编译。预处理指令由字符,#,标识,并且字符,#,必须是该行的第一个非空字符。,预处理指令最常见的三个用途是:完成条件编译、增加诊断来报告错误和警告、定义代码域。,C#,的预处理指令,2,C#,预处理命令,说明,#define,#,undef,用于定义一个符号,后取消对一个符号得定义。如果定义了一个符号,那么在,#if,指令中使用时这个符号计算为,true,。,#if,#,elif,#else,#,endif,类似,C#,中得,if,、,elseif,和,else,语句,#line,改变行好序
20、列,并且可以标识该行得源文件,#region,#,endregion,用于指定一个代码块,使用,Visual,studio.NET,的大纲特性时可以展开或折叠这个代码块,#error,导致编译器报告一个致命错误,#warming,导致编译器报告一个警告,并继续处理,unsafe,与,fixed,托管代码,(managed code),:由公共语言运行库环境(而不是直接由操作系统)执行的代码。托管代码应用程序可以获得公共语言运行库服务,例如自动垃圾回收、运行库类型检查和安全支持等。这些服务帮助提供独立于平台和语言的、统一的托管代码应用程序行为。,非托管代码(,Unmanaged Code,):在
21、公共语言运行库环境的外部,由操作系统直接执行的代码。非托管代码必须提供自己的垃圾回收、类型检查、安全支持等服务;它与托管代码不同,后者从公共语言运行库中获得这些服务。,为了保持类型安全,默认情况下,,C#,不支持指针算法。不过,通过使用,unsafe,关键字,可以定义可使用指针的不安全上下文。,C#,中的不安全代码不一定是危险的;只是其安全性无法由,CLR,进行验证的代码。,unsafe static void,ChangeValue(int,*,pInt,),*,pInt,=23;,上面的代码由于是在,CLR,下托管执行,为了减少内存碎片,C#,的自动垃圾回收机制会允许已经分配的内存在运行时
22、进行位置调整,所以如果我们多次调用的话就可能导致指针指向其他的变量。比如*,pInt,为指向一个变量的地址为,1001,,,CLR,在重新内存整理分配后该变量就存储在地址为,5001,的地方。而原来,1001,的地方可能会被分配其他变量,要解决这个问题我们就需要使用,fixed,关键字。,fixed,语句禁止垃圾回收器重定位可移动的变量,只有在执行完,fixed,模块后,指针所指向的对象才能被移动。,fixed,语句只能出现在不安全的上下文中。,fixed,还可用于创建固定大小的缓冲区。,unsafe,与,fixed,using,System;,class,CaryData,public,in
23、t,data,;,class,CProgram,unsafe static void,ChangeValue(,int,*,pInt,),*,pInt,=23;,public unsafe static void,Main(),CaryData,cd,=,new,CaryData,();,Console,.WriteLine,(,改变前,:0,cd.data,);,fixed,(,int,*p=&,cd.data,),ChangeValue(p,);,Console,.WriteLine,(,改变后,:0,cd.data,);,unsafe,与,fixed,只有执行完此模块,指针,p,的地址才允许改变,The End,Thank you!,






