《C#第6章面向对象程序设计.ppt》由会员分享,可在线阅读,更多相关《C#第6章面向对象程序设计.ppt(73页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、第第6章面向对象程序设计章面向对象程序设计 6.1 面向对象程序设计概述面向对象程序设计概述6.2 命名空间命名空间6.3 类类6.4 对象对象6.5 构造函数和析构函数构造函数和析构函数6.6 静态成员静态成员 6.7 属性属性6.8 方法方法 6.9 索引器索引器6.10 委托委托6.11 事件事件6.12 运算符重载运算符重载6.13 类的转换类的转换 6.1 面向对象程序设计概述面向对象程序设计概述 6.1.1 面向对象的基本概念面向对象的基本概念l 类和对象类和对象l 属性、方法和事件属性、方法和事件l 封装封装l 继承继承l 重载与重写重载与重写6.1.2 面向对象的优点面向对象的
2、优点l 维护简单。维护简单。l 可扩充性。可扩充性。l 代码重用。代码重用。6.2 命名空间命名空间6.2.1 命名空间概述命名空间概述 在在.NET中,类是通过命名空间(中,类是通过命名空间(namespace)来组织的。)来组织的。命名空间提供了可以将类分成逻辑组的方法,将系统中的大命名空间提供了可以将类分成逻辑组的方法,将系统中的大量类库有序地组织起来,使得类更容易使用和管理。量类库有序地组织起来,使得类更容易使用和管理。可以将命名空间想像成文件夹,类的文件夹就是命名空间,可以将命名空间想像成文件夹,类的文件夹就是命名空间,不同的命名空间内,可以定义许多类。在每个命名空间下,不同的命名空
3、间内,可以定义许多类。在每个命名空间下,所有的类都是所有的类都是“独立独立”且且“唯一唯一”的。的。6.2.2 使用命名空间使用命名空间 在在C#中,使用命名空间有两种方式,一种是明确指出命名中,使用命名空间有两种方式,一种是明确指出命名空间的位置,另一种是通过空间的位置,另一种是通过using关键字引用命名空间。关键字引用命名空间。直接定位在应用程序中,任何一个命名空间都可以在代码中直接定位在应用程序中,任何一个命名空间都可以在代码中直接使用。例如:直接使用。例如:System.Console.WriteLine(ABC);这个语句是调用了这个语句是调用了System命名空间中命名空间中Co
4、nsole类的类的WriteLine方法。方法。1)使用)使用using关键字关键字 在应用程序中要使用一个命名空间,还可以采取引用命名空在应用程序中要使用一个命名空间,还可以采取引用命名空间的方法,在引用后,应用程序中就可使用该命名空间内的任间的方法,在引用后,应用程序中就可使用该命名空间内的任一个类了。引用命名空间的方法是利用一个类了。引用命名空间的方法是利用using关键字,其使用格关键字,其使用格式如下:式如下:using 别名别名=命名空间命名空间或或 using 别名别名=命名空间命名空间.成员成员 2)自定义命名空间)自定义命名空间 在在C#中,除了使用系统的命名空间外,还可以在
5、应用程中,除了使用系统的命名空间外,还可以在应用程序中自已声明命名空间。其使用语法格式如下:序中自已声明命名空间。其使用语法格式如下:namespace命名空间名称命名空间名称 命名空间定义体命名空间定义体 其中,其中,“命名空间名称命名空间名称”指出命名空间的唯一名称,必须指出命名空间的唯一名称,必须是有效的是有效的C#标识符。例如,在应用程序中自定义标识符。例如,在应用程序中自定义Ns1命名命名空间:空间:namespace Ns1 class A class B 6.3类类6.3.1类的声明类的声明类的声明语法格式如下:类的声明语法格式如下:类的修饰符类的修饰符 class 类名类名:基
6、类名基类名 /类的成员类的成员;类的修饰符类的修饰符说明说明public公有类。表示不受限制对该类的访问。公有类。表示不受限制对该类的访问。protected保护类。表示只能从所在类和所在类派生的子类进行访问。保护类。表示只能从所在类和所在类派生的子类进行访问。internal内部类。只有其所在类才能访问。内部类。只有其所在类才能访问。private私有类。只有该类才能访问。私有类。只有该类才能访问。abstract抽象类。表示该类是一个不完整的类,不允许建立类的实抽象类。表示该类是一个不完整的类,不允许建立类的实例。例。sealed密封类。不允许从该类派生新的类。密封类。不允许从该类派生新的
7、类。例如,以下声明了一个例如,以下声明了一个Person类:类:public class Personpublic int pno;/编号编号 public string pname;/姓名姓名public void setdata(int no,string name)pno=no;pname=name;public void dispdata()Console.WriteLine(0 1,pno,pname);6.3.2类的成员类的成员类的成员类的成员说明说明字段字段字段存储类要满足其设计所需要的数据,亦称为数据成员。字段存储类要满足其设计所需要的数据,亦称为数据成员。属性属性属性是类中可
8、以像类中的字段一样被访问的方法。属性可以为类字属性是类中可以像类中的字段一样被访问的方法。属性可以为类字段提供保护,避免字段在对象不知道的情况下被更改。段提供保护,避免字段在对象不知道的情况下被更改。方法方法方法定义类可以执行的操作。方法可以接受提供输入数据的参数,方法定义类可以执行的操作。方法可以接受提供输入数据的参数,并且可以通过参数返回输出数据。方法还可以不使用参数而直接返并且可以通过参数返回输出数据。方法还可以不使用参数而直接返回值。回值。事件事件事件是向其他对象提供有关事件发生(如单击按钮或成功完成某个事件是向其他对象提供有关事件发生(如单击按钮或成功完成某个方法)通知的一种方式。方
9、法)通知的一种方式。索引器索引器索引器允许以类似于数组的方式为对象建立索引。索引器允许以类似于数组的方式为对象建立索引。运算符运算符运算符是对操作数执行运算的术语或符号,如运算符是对操作数执行运算的术语或符号,如+、*、);p1.dispoint();TPoint p2=new TPoint();/定义对象定义对象p2 p2.setpoint(8,3);Console.Write(第二个点第二个点=);p2.dispoint();6.5 构造函数和析构函数构造函数和析构函数6.5.1构造函数构造函数1.什么是构造函数什么是构造函数 构造函数是在创建给定类型的对象时执行的类方法。构构造函数是在创
10、建给定类型的对象时执行的类方法。构造函数具有如下性质:造函数具有如下性质:l 构造函数的名称与类的名称相同。构造函数的名称与类的名称相同。l 构造函数尽管是一个函数,但没有任何类型,即它既不构造函数尽管是一个函数,但没有任何类型,即它既不属于返回值函数也不属于属于返回值函数也不属于void函数。函数。l 一个类可以有多个构造函数,但所有构造函数的名称都一个类可以有多个构造函数,但所有构造函数的名称都必须相同,它们的参数各不相同,即构造函数可以重载。必须相同,它们的参数各不相同,即构造函数可以重载。l 当类对象创建时,构造函数会自动地执行;由于它们没当类对象创建时,构造函数会自动地执行;由于它们
11、没有返回类型,因此不能像其他函数那样进行调用。有返回类型,因此不能像其他函数那样进行调用。l 当类对象声明时,调用哪一个构造函数取决于传递给它当类对象声明时,调用哪一个构造函数取决于传递给它的参数类型。的参数类型。l 构造函数不能被继承。构造函数不能被继承。2.调用构造函数调用构造函数当定义类对象时,构造函数会自动执行。当定义类对象时,构造函数会自动执行。1)调用默认构造函数)调用默认构造函数 不带参数的构造函数称为默认构造函数。无论何时,只要不带参数的构造函数称为默认构造函数。无论何时,只要使用使用new运算符实例化对象,并且不为运算符实例化对象,并且不为new提供任何参数,就提供任何参数,
12、就会调用默认构造函数。假设一个类包含有默认构造函数,调会调用默认构造函数。假设一个类包含有默认构造函数,调用默认构造函数的语法如下:用默认构造函数的语法如下:类名类名 对象名对象名=new 类名类名();如果没有为对象提供构造函数,则默认情况下如果没有为对象提供构造函数,则默认情况下 C#将创建将创建一个构造函数,该构造函数实例化对象,并将所有成员变量一个构造函数,该构造函数实例化对象,并将所有成员变量设置为相应的默认值。设置为相应的默认值。2)调用带参数的构造函数)调用带参数的构造函数 假设一个类中包含有带参数的构造函数,调用这种带参数假设一个类中包含有带参数的构造函数,调用这种带参数的构造
13、函数的语法如下:的构造函数的语法如下:类名类名 对象名对象名=new 类名类名(参数表参数表);【例【例6.2】设计一个控制台应用程序,说明调用构造函数的过程。设计一个控制台应用程序,说明调用构造函数的过程。namespace Proj6_2 class Program public class TPoint1 /声明类声明类TPoint1 int x,y;/类的私有变量类的私有变量 public TPoint1()/默认的构造函数默认的构造函数 public TPoint1(int x1,int y1)/带参数的构造函数带参数的构造函数 x=x1;y=y1;public void dispo
14、int()Console.WriteLine(0,1),x,y);static void Main(string args)TPoint1 p1=new TPoint1();/调用默认的构造函数调用默认的构造函数 Console.Write(第一个点第一个点=);p1.dispoint();TPoint1 p2=new TPoint1(8,3);/调用带参数的构造函数调用带参数的构造函数 Console.Write(第二个点第二个点=);p2.dispoint();6.5.2析构函数析构函数 1.什么是析构函数什么是析构函数 在对象不再需要时,希望确保它所占的存储空间能被收在对象不再需要时,希
15、望确保它所占的存储空间能被收回。回。C#中提供了析构函数用于专门释放被占用的系统资源。中提供了析构函数用于专门释放被占用的系统资源。析构函数具有如下性质:析构函数具有如下性质:l 析构函数在类对象销毁时自动执行。析构函数在类对象销毁时自动执行。l 一个类只能有一个析构函数,而且析构函数没有参数,一个类只能有一个析构函数,而且析构函数没有参数,即析构函数不能重载。即析构函数不能重载。l 析构函数的名称是析构函数的名称是“”加上类的名称(中间没有空格)。加上类的名称(中间没有空格)。l 与构造函数一样,析构函数也没有返回类型。与构造函数一样,析构函数也没有返回类型。l 析构函数不能被继承。析构函数
16、不能被继承。2.调用析构函数调用析构函数当一个对象被系统销毁时自动调用类的析构函数。当一个对象被系统销毁时自动调用类的析构函数。【例【例6.3】设计一个控制台应用程序,说明调用析构函数的过程。设计一个控制台应用程序,说明调用析构函数的过程。using System;namespace Proj6_3 class Program public class TPoint2/声明类声明类TPoint2 int x,y;public TPoint2(int x1,int y1)/带参数的构造函数带参数的构造函数 x=x1;y=y1;TPoint2()Console.WriteLine(点点=(0,1)
17、,x,y);static void Main(string args)TPoint2 p1=new TPoint2(2,6);TPoint2 p2=new TPoint2(8,3);6.6 静态成员静态成员 6.6.1 静态字段静态字段 静态字段是类中所有对象共享的成员,而不是某个对静态字段是类中所有对象共享的成员,而不是某个对象的成员,也就是说静态字段的存储空间不是放在每个对象的成员,也就是说静态字段的存储空间不是放在每个对象中,而是和方法一样放在类公共区中。象中,而是和方法一样放在类公共区中。对静态字段的操作和一般字段一样,定义为私有的静对静态字段的操作和一般字段一样,定义为私有的静态字段
18、不能被外界访问。静态字段的使用方法如下:态字段不能被外界访问。静态字段的使用方法如下:(1)静态字段的定义与一般字段相似,但前面要加上)静态字段的定义与一般字段相似,但前面要加上static关键词。关键词。(2)在访问静态字段时采用如下格式:)在访问静态字段时采用如下格式:类名类名.静态字段名静态字段名6.6.2 静态方法静态方法 静态方法与静态字段类似,也是从属于类,都是类的静静态方法与静态字段类似,也是从属于类,都是类的静态成员。只要类存在,静态方法就可以使用,静态方法的态成员。只要类存在,静态方法就可以使用,静态方法的定义是在一般方法定义前加上定义是在一般方法定义前加上static关键字
19、。调用静态方关键字。调用静态方法的格式如下:法的格式如下:类名类名.静态方法名静态方法名(参数表参数表);注意:静态方法只能访问静态字段、其他静态方法和类注意:静态方法只能访问静态字段、其他静态方法和类以外的函数及数据,不能访问类中的非静态成员(因为非以外的函数及数据,不能访问类中的非静态成员(因为非静态成员只有对象存在时才有意义)。但静态字段和静态静态成员只有对象存在时才有意义)。但静态字段和静态方法可由任意访问权限许可的成员访问。方法可由任意访问权限许可的成员访问。6.7属性属性6.7.1什么是属性什么是属性 属性描述了对象的具体特性,它提供了对类或对象成员的属性描述了对象的具体特性,它提
20、供了对类或对象成员的访问。访问。C#中的属性更充分地体现了对象的封装性,属性不直接中的属性更充分地体现了对象的封装性,属性不直接操作类的字段,而是通过访问器进行访问。操作类的字段,而是通过访问器进行访问。6.7.2属性声明属性声明 属性在类模块里是采用下面的方式进行声明的,即指定属性在类模块里是采用下面的方式进行声明的,即指定变量的访问级别、属性的类型、属性的名称,然后是变量的访问级别、属性的类型、属性的名称,然后是get访访问器或者问器或者set访问器代码块。其语法格式如下:访问器代码块。其语法格式如下:修饰符修饰符 数据类型数据类型 属性名称属性名称 get访问器访问器 set访问器访问器
21、 其中,修饰符有其中,修饰符有new、public、protected、internal、private、static、virtual、override和和abstract。【例【例6.7】设计一个控制台应用程序,说明属性的使用。设计一个控制台应用程序,说明属性的使用。using System;namespace Proj6_7 public class TPoint3/声明类声明类TPoint3 int x,y;public int px get/get访问器访问器 return x;set/set访问器访问器 x=value;public int py get/get访问器访问器 retu
22、rn y;set/set访问器访问器 y=value;class Program static void Main(string args)TPoint3 p=new TPoint3();p.px=3;p.py=8;/属性写操作属性写操作 Console.WriteLine(点点=(0,1),p.px,p.py);/属性读操作属性读操作 点点=(3,8)6.8 方法方法 6.8.1 什么是方法什么是方法 方法包含一系列的代码块。从本质上来讲,方法就是方法包含一系列的代码块。从本质上来讲,方法就是和类相关联的动作,是类的外部界面。和类相关联的动作,是类的外部界面。用户可以通过外部界面来操作类的私
23、有字段。用户可以通过外部界面来操作类的私有字段。6.8.2 方法的定义方法的定义定义方法的基本格式如下:定义方法的基本格式如下:修饰符修饰符 返回类型返回类型 方法名方法名(参数列表参数列表)/方法的具体实现方法的具体实现;6.8.3 方法的返回值方法的返回值 方法可以向调用方返回某一个特定的值。如果返回类型方法可以向调用方返回某一个特定的值。如果返回类型不是不是void,则该方法可以用,则该方法可以用return关键字来返回值,关键字来返回值,return 还可以用来停止方法的执行。还可以用来停止方法的执行。例如,以下类例如,以下类MyClass3中的中的addnum方法用方法用return
24、关键字关键字来返回值:来返回值:public class MyClass3 int num=0;public int addnum(int num1)return num+num1;6.8.4 方法的参数方法的参数 方法中的参数是保证不同的方法间互动的重要桥梁,方方法中的参数是保证不同的方法间互动的重要桥梁,方便用户对数据的操作。便用户对数据的操作。C#中方法的参数有中方法的参数有4种类型。种类型。1.值参数值参数 不含任何修饰符,当利用值向方法传递参数时,编译程不含任何修饰符,当利用值向方法传递参数时,编译程序给实参的值做一份拷贝,并且将此拷贝传递给该方法,序给实参的值做一份拷贝,并且将此拷
25、贝传递给该方法,被调用的方法不会修改内存中实参的值,所以使用值参数被调用的方法不会修改内存中实参的值,所以使用值参数时可以保证实际值的安全性。在调用方法时,如果形参的时可以保证实际值的安全性。在调用方法时,如果形参的类型是值参数的话,调用的实参的表达式必须保证是正确类型是值参数的话,调用的实参的表达式必须保证是正确的值表达式。的值表达式。例如,前面例如,前面MyClass3类中类中addnum方法中的参数就是值方法中的参数就是值参数。参数。2.引用型参数引用型参数 以以ref修饰符声明的参数属引用型参数。引用型参数本身修饰符声明的参数属引用型参数。引用型参数本身并不创建新的存储空间,而是将实参
26、的存储地址传递给形并不创建新的存储空间,而是将实参的存储地址传递给形参,所以对形参的修改会影响原来实参的值。在调用方法参,所以对形参的修改会影响原来实参的值。在调用方法前,引用型实参必须被初始化,同时在调用方法时,对应前,引用型实参必须被初始化,同时在调用方法时,对应引用型参数的实参也必须使用引用型参数的实参也必须使用ref修饰。修饰。例如:例如:public class MyClass4 int num=0;public void addnum(int num1,ref int num2)num2=num+num1;class Program static void Main(string
27、args)int x=0;MyClass4 s=new MyClass4();s.addnum(5,ref x);Console.WriteLine(x);/输出:输出:5 3.输出参数输出参数 以以out修饰符声明的参数属输出参数。与引用型参数类修饰符声明的参数属输出参数。与引用型参数类似,输出型参数也不开辟新的内存区域。它与引用型参数似,输出型参数也不开辟新的内存区域。它与引用型参数的差别在于,调用方法前无需对变量进行初始化。输出型的差别在于,调用方法前无需对变量进行初始化。输出型参数用于传递方法返回的数据,参数用于传递方法返回的数据,out修饰符后应跟随与形参修饰符后应跟随与形参的类型相
28、同的类型,用来声明在方法返回后传递的变量经的类型相同的类型,用来声明在方法返回后传递的变量经过了初始化。过了初始化。例如:例如:public class MyClass5 int num=0;public void addnum(int num1,out int num2)num2=num+num1;class Program static void Main(string args)int x;MyClass5 s=new MyClass5();s.addnum(5,out x);Console.WriteLine(x);/输出:输出:5 4.数组型参数数组型参数 以以params修饰符声明
29、的参数属数组型参数。修饰符声明的参数属数组型参数。params关关键字可以指定在参数数目可变处采用参数的方法参数。在键字可以指定在参数数目可变处采用参数的方法参数。在方法声明中的方法声明中的params关键字之后不允许任何其他参数,关键字之后不允许任何其他参数,并且在方法声明中只允许一个并且在方法声明中只允许一个params关键字。有数组型关键字。有数组型参数就不能再有参数就不能再有ref 和和out修饰符。修饰符。例如:例如:public class MyClass6 int num=10;public void addnum(ref int sum,params int b)sum=num
30、;foreach(int item in b)sum+=item;class Program static void Main(string args)int a=new int3 1,2,3;int x=0;MyClass6 s=new MyClass6();s.addnum(ref x,a);Console.WriteLine(x);6.8.5 方法的重载方法的重载 方法的重载是指调用同一方法名,但是使用不同的数据方法的重载是指调用同一方法名,但是使用不同的数据类型参数或者次序不一致的参数。只要一个类中有两个以类型参数或者次序不一致的参数。只要一个类中有两个以上的同名方法,且使用的参数类型
31、或者个数不同,编译器上的同名方法,且使用的参数类型或者个数不同,编译器就可以判断在哪种情况下调用哪种方法了。就可以判断在哪种情况下调用哪种方法了。为此,为此,C#中引入了中引入了成员签名成员签名的概念。成员签名包含成的概念。成员签名包含成员的名称和参数列表,每个成员签名在类型中必须是唯一员的名称和参数列表,每个成员签名在类型中必须是唯一的,只要成员的参数列表不同,成员的名称可以相同。如的,只要成员的参数列表不同,成员的名称可以相同。如果同一个类有两个或多个这样的成员(方法、属性、构造果同一个类有两个或多个这样的成员(方法、属性、构造函数等),它们具有相同的名称和不同的参数列表,则称函数等),它
32、们具有相同的名称和不同的参数列表,则称该同类成员进行了重载,但它们的成员签名是不同的。该同类成员进行了重载,但它们的成员签名是不同的。例如,下面的代码实现了例如,下面的代码实现了MethodTest方法的重载(假方法的重载(假设都是某个类的成员),它们是不同的成员签名:设都是某个类的成员),它们是不同的成员签名:public int MethodTest(int i,int j)/重载方法重载方法1/代码代码public int MethodTest(int i)/重载方法重载方法2/代码代码public string MethodTest(string sr)/重载方法重载方法3/代码代码6
33、.9 索引器索引器6.9.1 什么是索引器什么是索引器 索引器提供了一种访问类或结构的方法,即允许按照索引器提供了一种访问类或结构的方法,即允许按照与数组相同的方式对类、结构或接口进行索引。它的引入与数组相同的方式对类、结构或接口进行索引。它的引入是为了使程序更加直观、易于理解。是为了使程序更加直观、易于理解。例如,可以有一个大学名称类例如,可以有一个大学名称类University,其中有一个,其中有一个name数组字段可能包含一些大学名称,数组字段可能包含一些大学名称,un是该类的一个是该类的一个对象,类中索引器允许访问这些大学名称,例如:对象,类中索引器允许访问这些大学名称,例如:un0=
34、清华大学清华大学;un1=北京大学北京大学;un3=武汉大学武汉大学;6.9.2 定义索引器定义索引器 要声明类或结构上的索引器,需使用要声明类或结构上的索引器,需使用this关键字,其语关键字,其语法格式如下:法格式如下:public int thisint index /索引器声明索引器声明 /get和和set访问器访问器 其中,其中,this关键字引用类的当前实例。从中看到,索引关键字引用类的当前实例。从中看到,索引器像对普通属性一样,为它提供器像对普通属性一样,为它提供get和和set方法,这些访问方法,这些访问器指定当使用该索引器时将引用到什么内部成员。器指定当使用该索引器时将引用到
35、什么内部成员。例如,带有索引器的例如,带有索引器的University类设计如下:类设计如下:public class University const int MAX=5;private string name=new stringMAX;public string thisint index /索引器索引器 get if(index=0&index=0&index MAX)nameindex=value;6.10委托委托6.10.1 什么是委托什么是委托 C+、Pascal和其他语言支持函数指针的概念,允许在和其他语言支持函数指针的概念,允许在运行时选择要调用的函数。运行时选择要调用的函数
36、。Java不提供任何具有函数指针不提供任何具有函数指针功能的结构,但功能的结构,但C#提供这种构造。通过使用提供这种构造。通过使用Delegate类,类,委托实例可以封装属于可调用实体的方法。委托实例可以封装属于可调用实体的方法。委托具有以下特点:委托具有以下特点:l 委托类似于委托类似于C+函数指针,但它是类型安全的。函数指针,但它是类型安全的。l 委托允许将方法作为参数进行传递。委托允许将方法作为参数进行传递。l 委托可用于定义回调方法。委托可用于定义回调方法。l 委托可以链接在一起。例如,可以对一个事件调用多个委托可以链接在一起。例如,可以对一个事件调用多个方法。方法。l 方法不需要与委
37、托签名精确匹配。方法不需要与委托签名精确匹配。6.10.2 定义和使用委托定义和使用委托定义和使用委托有定义和使用委托有3个步骤,即声明、实例化和调用。个步骤,即声明、实例化和调用。1.声明委托类型声明委托类型 声明委托类型就是告诉编译器这种类型代表了哪种类型声明委托类型就是告诉编译器这种类型代表了哪种类型的方法。使用以下语法声明委托类型:的方法。使用以下语法声明委托类型:修饰符修饰符 delegate 返回类型返回类型 委托类型名委托类型名(参数列表参数列表);在声明一个委托类型时,每个委托类型都描述参数的数在声明一个委托类型时,每个委托类型都描述参数的数目和类型,以及它可以引用的方法的返回
38、类型。每当需要目和类型,以及它可以引用的方法的返回类型。每当需要一组新的参数类型或新的返回类型时,都必须声明一个新一组新的参数类型或新的返回类型时,都必须声明一个新的委托类型。的委托类型。例如:例如:private delegate void mydelegate(int n);上述代码声明了一个委托上述代码声明了一个委托mydelegate,该委托类型可以,该委托类型可以引用一个采用引用一个采用int作为参数并返回作为参数并返回void的方法。的方法。2.实例化委托实例化委托 声明了委托类型后,必须创建一个它的实例,即创建声明了委托类型后,必须创建一个它的实例,即创建委托对象并使之与特定方法
39、关联。定义委托对象的语法委托对象并使之与特定方法关联。定义委托对象的语法格式如下:格式如下:委托类型名委托类型名 委托对象名委托对象名;例如,以下语句创建了例如,以下语句创建了mydelegate委托的一个委托对委托的一个委托对象象p:mydelegate p;另外,委托对象还需实例化为调用的方法,通常将这些方另外,委托对象还需实例化为调用的方法,通常将这些方法放在一个类中(也可以将这些方法放在程序的法放在一个类中(也可以将这些方法放在程序的Program类类中),假设一个中),假设一个MyDeClass类如下:类如下:class MyDeClass public void fun1(int
40、n)Console.WriteLine(0的的2倍倍=1,n,2*n);public void fun2(int n)Console.WriteLine(0的的3倍倍=1,n,3*n);可以通过以下语句实例化委托对象可以通过以下语句实例化委托对象p:MyDeClass obj=new MyDeClass();mydelegate p=new mydelegate(obj.fun1);其中,其中,MyDeClass类中的类中的fun1方法有一个方法有一个int形参,其返形参,其返回类型为回类型为void,它必须与,它必须与mydelegate类型的声明相一致。类型的声明相一致。3.调用委托调用委
41、托 创建委托对象后,通常将委托对象传递给将调用该委创建委托对象后,通常将委托对象传递给将调用该委托的其他代码。通过委托对象的名称(后面跟着要传递托的其他代码。通过委托对象的名称(后面跟着要传递给委托的参数,放在括号内)调用委托对象。其使用语给委托的参数,放在括号内)调用委托对象。其使用语法格式如下:法格式如下:委托对象名委托对象名(实参列表实参列表);例如,以下语句调用委托例如,以下语句调用委托p:p(100);委托对象是不可变的,即设置与它们匹配的签名后就委托对象是不可变的,即设置与它们匹配的签名后就不能再更改签名了。但是,如果其他方法具有同一签名,不能再更改签名了。但是,如果其他方法具有同
42、一签名,也可以指向该方法。例如:也可以指向该方法。例如:MyDeClass obj=new MyDeClass();mydelegate p=new mydelegate(obj.fun1);p(5);p=new mydelegate(obj.fun2);p(3);【例【例6.9】设计一个控制台应用程序,说明委托的使用。设计一个控制台应用程序,说明委托的使用。using System;namespace Proj6_9 delegate double mydelegate(double x,double y);/声明委托类型声明委托类型 class MyDeClass public doubl
43、e add(double x,double y)return x+y;public double sub(double x,double y)return x-y;public double mul(double x,double y)return x*y;public double div(double x,double y)return x/y;class Program static void Main(string args)MyDeClass obj=new MyDeClass();mydelegate p=new mydelegate(obj.add);Console.WriteL
44、ine(5+8=0,p(5,8);p=new mydelegate(obj.sub);Console.WriteLine(5-8=0,p(5,8);p=new mydelegate(obj.mul);Console.WriteLine(5*8=0,p(5,8);p=new mydelegate(obj.div);Console.WriteLine(5/8=0,p(5,8);前面代码中前面代码中p作为引用类型,也可以改为值类型,等价的作为引用类型,也可以改为值类型,等价的主函数可以如下改为:主函数可以如下改为:static void Main(string args)MyDeClass obj=
45、new MyDeClass();mydelegate p=obj.add;Console.WriteLine(5+8=0,p(5,8);p=obj.sub;Console.WriteLine(5-8=0,p(5,8);p=obj.mul;Console.WriteLine(5*8=0,p(5,8);p=obj.div;Console.WriteLine(5/8=0,p(5,8);6.10.3 委托对象封装多个方法委托对象封装多个方法 委托对象可以封装多个方法,这些方法的集合称为调用委托对象可以封装多个方法,这些方法的集合称为调用列表。委托使用列表。委托使用“+”、“-”、“+=”和和“-=”等
46、运算符向等运算符向调用列表中增加或移除事件处理方法。调用列表中增加或移除事件处理方法。【例【例6.10】设计一个控制台应用程序,说明委托对象封装设计一个控制台应用程序,说明委托对象封装多个方法的使用。多个方法的使用。using System;namespace Proj6_10 delegate void mydelegate(double x,double y);/声明委托类型声明委托类型 class MyDeClass public void add(double x,double y)Console.WriteLine(0+1=2,x,y,x+y);public void sub(dou
47、ble x,double y)Console.WriteLine(0-1=2,x,y,x-y);public void mul(double x,double y)Console.WriteLine(0*1=2,x,y,x*y);public void div(double x,double y)Console.WriteLine(0/1=2,x,y,x/y);class Program static void Main(string args)MyDeClass obj=new MyDeClass();mydelegate p,a;a=obj.add;p=a;/将将add方法添加到调用列表中
48、方法添加到调用列表中 a=obj.sub;p+=a;/将将sub方法添加到调用列表中方法添加到调用列表中 a=obj.mul;p+=a;/将将mul方法添加到调用列表中方法添加到调用列表中 a=obj.div;p+=a;/将将div方法添加到调用列表中方法添加到调用列表中 p(5,8);6.10.4 使委托与匿名方法关联使委托与匿名方法关联 所谓匿名方法就是没有方法名称的方法。当将委托与匿名所谓匿名方法就是没有方法名称的方法。当将委托与匿名方法关联时,直接给出方法的函数体,其一般语法格式如下:方法关联时,直接给出方法的函数体,其一般语法格式如下:delegate 返回类型返回类型 委托类型名委
49、托类型名(参数列表参数列表);委托类型名委托类型名 委托对象名委托对象名=返回类型返回类型(参数列表参数列表)/*匿名方法代码匿名方法代码*/;托对象名托对象名(实参列表实参列表)第第1个语句声明委托类型;第个语句声明委托类型;第2个语句定义匿名方法并将其个语句定义匿名方法并将其与委托对象关联;第与委托对象关联;第3个语句调用委托。个语句调用委托。例如,以下程序段就是使委托与匿名方法关联,并调用例如,以下程序段就是使委托与匿名方法关联,并调用该委托:该委托:delegate void mydelegate(string mystr);/声明委托类型声明委托类型 class Program st
50、atic void Main(string args)mydelegate p=delegate(string mystr)Console.WriteLine(mystr);p(String);/输出:输出:String 6.11事件事件 6.11.1 什么是事件什么是事件 事件是类在发生其关注的事情时用来提供通知的一种方式。事件是类在发生其关注的事情时用来提供通知的一种方式。例如,封装用户界面控件的类可以定义一个在用户单击时候例如,封装用户界面控件的类可以定义一个在用户单击时候发生的一个事件。控件类不关心单击按钮时候发生了什么,发生的一个事件。控件类不关心单击按钮时候发生了什么,但是它需要告