《C#程序设计教程第5章.ppt》由会员分享,可在线阅读,更多相关《C#程序设计教程第5章.ppt(49页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、2023/4/21C#程序设计经典程序设计经典教程教程第五章第五章 面向对象的高级程序设计1.总体要求总体要求l掌握静态类与静态类成员的定义与使用。掌握静态类与静态类成员的定义与使用。l理解类的继承性与多态性,掌握其应用方法。理解类的继承性与多态性,掌握其应用方法。l理解抽象类、接口的概念,掌握抽象类与接口的定义及使用理解抽象类、接口的概念,掌握抽象类与接口的定义及使用方法。方法。l理解嵌套类、分部类和命名空间的概念,掌握嵌套类、分部理解嵌套类、分部类和命名空间的概念,掌握嵌套类、分部类和命名空间的使用方法。类和命名空间的使用方法。2.相关知识点相关知识点l熟悉熟悉C#的结构、类、数组的区别。
2、的结构、类、数组的区别。l熟悉类和类成员的定义与使用熟悉类和类成员的定义与使用l熟悉方法的定义与使用等基本操作。熟悉方法的定义与使用等基本操作。3.学习重点学习重点l静态成员与静态类静态成员与静态类l类的继承性与多态性类的继承性与多态性l抽象类与接口定义与使用。抽象类与接口定义与使用。4.学习难点学习难点l静态成员的作用,静态方法和实例方法的区别静态成员的作用,静态方法和实例方法的区别l多态的概念和实现,虚方法和抽象方法的区别多态的概念和实现,虚方法和抽象方法的区别l接口的作用和使用,抽象方法和接口的区别接口的作用和使用,抽象方法和接口的区别第五章第五章 面向对象的高级程序设计第五章第五章 面
3、向对象的高级程序设计主要内容主要内容l l5.1 静态成员与静态类静态成员与静态类 l l5.2 类的继承性与多态性类的继承性与多态性l l5.3 抽象类与接口抽象类与接口l l5.4 嵌套类、分部类与命名空间嵌套类、分部类与命名空间5.1 静态成员与静态类静态成员与静态类 l5.1.1 静态成员静态成员l5.1.2 静态构造函数静态构造函数l5.1.3 静态类静态类返回返回5.1.1 静态成员静态成员l静态成员通过静态成员通过static关键字来标识,可以是静态方法、字段、关键字来标识,可以是静态方法、字段、属性或事件。属性或事件。l静态成员与非静态成员的不同在于:静态成员属于类,而静态成员
4、与非静态成员的不同在于:静态成员属于类,而不属于类的实例,因此需要通过类而不是通过类的实例来不属于类的实例,因此需要通过类而不是通过类的实例来访问;而非静态成员则总是与特定的实例访问;而非静态成员则总是与特定的实例(对象对象)相联系。相联系。l在实际应用中,当类的成员所引用或操作的信息是关于类在实际应用中,当类的成员所引用或操作的信息是关于类而不是类的实例时,就应该设置为静态成员。例如,想统而不是类的实例时,就应该设置为静态成员。例如,想统计同类对象的数量,就可使用静态字段和静态方法来实现计同类对象的数量,就可使用静态字段和静态方法来实现5.1.1 静态成员静态成员l【实例实例5-1】利用静态
5、成员统计人数。利用静态成员统计人数。5.1.2 静态构造函数静态构造函数l类的构造函数也可以是静态的,静态构造函数不是为了创类的构造函数也可以是静态的,静态构造函数不是为了创建对象而设计的,而是用来初始化类,只有非静态的构造建对象而设计的,而是用来初始化类,只有非静态的构造函数才用来创建对象(用于创建对象的构造函数称为实例函数才用来创建对象(用于创建对象的构造函数称为实例构造函数)。由于静态构造函数并不对类的特定实例进行构造函数)。由于静态构造函数并不对类的特定实例进行操作,所以也称为全局或共享构造函数。操作,所以也称为全局或共享构造函数。l在在C#应用程序中,不能直接调用静态构造函数。静态构
6、造应用程序中,不能直接调用静态构造函数。静态构造函数在类的第一个实例创建之前或者调用类的任何静态方函数在类的第一个实例创建之前或者调用类的任何静态方法之前执行,而且最多执行一次。因此,静态构造函数适法之前执行,而且最多执行一次。因此,静态构造函数适合于对类的静态数据成员进行初始化。合于对类的静态数据成员进行初始化。5.1.2 静态构造函数静态构造函数l静态构造函数可以与实例构造函数共存,其一般形式如下:静态构造函数可以与实例构造函数共存,其一般形式如下:static 静态构造函数名静态构造函数名()/语句语句;l其中,静态构造函数名与类名相同,声明静态构造函数时其中,静态构造函数名与类名相同,
7、声明静态构造函数时不能带访问修饰符(如不能带访问修饰符(如public),并且不能有任何参数列),并且不能有任何参数列表和返回值。表和返回值。5.1.2 静态构造函数静态构造函数l我们可以在我们可以在【实例实例5-1】的基础上增加一个静态构造函数,的基础上增加一个静态构造函数,结果就会不同结果就会不同5.1.3 静态类静态类l静态类使用静态类使用static关键字来声明,以指示它仅包含静态成员,关键字来声明,以指示它仅包含静态成员,不能使用不能使用new关键字创建静态类的实例。在实际应用中,关键字创建静态类的实例。在实际应用中,当类中的成员不与特定对象关联的时候,就可以把它创建当类中的成员不与
8、特定对象关联的时候,就可以把它创建为静态类。为静态类。l静态类有下以特点:静态类有下以特点:l(1)静态类仅包含静态成员;静态类仅包含静态成员;l(2)静态类不能被实例化;静态类不能被实例化;l(3)静态类是密封的;静态类是密封的;l(4)静态类不能包含实例构造函数静态类不能包含实例构造函数 5.1.3 静态类静态类l由于静态类是密封的,因此不可被继承。静态类不能包含由于静态类是密封的,因此不可被继承。静态类不能包含实例构造函数,但仍可声明静态构造函数,以分配初始值实例构造函数,但仍可声明静态构造函数,以分配初始值或设置某个静态状态。或设置某个静态状态。(关于密封和继承将在下节进行讨论关于密封
9、和继承将在下节进行讨论)。l静态类的优点如下:静态类的优点如下:l(1)编译器能够自动执行检查,以确保不添加实例成员;编译器能够自动执行检查,以确保不添加实例成员;l(2)静态类能够使程序的实现更简单、迅速,因为不必创建静态类能够使程序的实现更简单、迅速,因为不必创建对象就能调用其方法。对象就能调用其方法。5.2 类的继承性与多态性类的继承性与多态性l5.2.1 类的继承性类的继承性l5.2.2 类的多态性类的多态性返回返回5.2.1 类的继承性类的继承性l当一个类从另一个类派生出来时,派生类就具有了基类中当一个类从另一个类派生出来时,派生类就具有了基类中的所有成员,这样,基类中定义这些成员的
10、代码,不需要的所有成员,这样,基类中定义这些成员的代码,不需要在派生类定义中重写,在派生类定义中,只需定义派生类在派生类定义中重写,在派生类定义中,只需定义派生类自己的成员即可。这样,既提高了代码的重用性,从而提自己的成员即可。这样,既提高了代码的重用性,从而提高了程序设计的效率,又提供了已有程序设计的可扩展性。高了程序设计的效率,又提供了已有程序设计的可扩展性。类的继承为面向对象程序设计构建一个分层类结构体系创类的继承为面向对象程序设计构建一个分层类结构体系创造了条件,而造了条件,而.NET框架类库就是一个庞大的分层类结构体框架类库就是一个庞大的分层类结构体系。其中系。其中Object类是一
11、个最上层的基类,其他所有类都是类是一个最上层的基类,其他所有类都是直接或间接由直接或间接由Object类继承而来的。即使用户自定义的类类继承而来的。即使用户自定义的类没有指定继承关系,系统仍然将该类作为没有指定继承关系,系统仍然将该类作为Object类的派生类的派生类。类。5.2.1 类的继承性类的继承性l在在C#中,类的继承遵循以下原则:中,类的继承遵循以下原则:l(1)派生类只能从一个类中继承,即单继承。派生类只能从一个类中继承,即单继承。l(2)派生类自然继承基类的成员,但不能继承基类的构造函派生类自然继承基类的成员,但不能继承基类的构造函数数l(3)类的继承可以传递,例如:假设类类的继
12、承可以传递,例如:假设类C继承于类继承于类B,类,类B又又继承类继承类A,那么,那么C类即具有类类即具有类B和类和类A的成员,可以认为类的成员,可以认为类A是类是类C的祖先类。的祖先类。5.2.1 类的继承性类的继承性l1派生类的声明派生类的声明 在在C#中,派生类可以拥有自己的成员,也可以隐式地中,派生类可以拥有自己的成员,也可以隐式地从它的基类继承所有成员,包括方法、字段、属性和事件,从它的基类继承所有成员,包括方法、字段、属性和事件,但私有成员、构造函数和析构函数等除外。另外,派生类但私有成员、构造函数和析构函数等除外。另外,派生类只能从一个类中继承,即单继承。只能从一个类中继承,即单继
13、承。lC#中声明派生类的一般形式如下:中声明派生类的一般形式如下:访问修饰符访问修饰符 class 类名类名:基类名基类名 类的成员类的成员;5.2.1 类的继承性类的继承性l2构造函数的调用构造函数的调用l在在C#中,派生类不能继承其基类的构造函数,但是,在创中,派生类不能继承其基类的构造函数,但是,在创建对象时,会调用构造函数,为对象分配内存并初始化对建对象时,会调用构造函数,为对象分配内存并初始化对象的数据。创建派生类对象时,为完成其基类部份的成员象的数据。创建派生类对象时,为完成其基类部份的成员初始化,会调用基类的构造函数。其调用构造函数的顺序初始化,会调用基类的构造函数。其调用构造函
14、数的顺序是先调用基类构造函数,再调用派生类的构造函数,以完是先调用基类构造函数,再调用派生类的构造函数,以完成数据成员分配内存空间并进行初始化的工作。成数据成员分配内存空间并进行初始化的工作。l类的继承可以传递,例如:假设类类的继承可以传递,例如:假设类C继承于类继承于类B,类,类B又继又继承类承类A,那么,那么C类即具有类类即具有类B和类和类A的成员,可以认为类的成员,可以认为类A是是类类C的祖先类。在这种情况下,构造函数的调用次序按由的祖先类。在这种情况下,构造函数的调用次序按由高到低顺序依次调用,即先调用高到低顺序依次调用,即先调用A的构造函数,再调用的构造函数,再调用B的的构造函数。最
15、后调用构造函数。最后调用C的构造函数。的构造函数。5.2.1 类的继承性类的继承性l【实例实例5-2】继承中的构造函数调用演示。继承中的构造函数调用演示。5.2.1 类的继承性类的继承性l如果把基类的构造函数如果把基类的构造函数public Animal()改为如下形式:改为如下形式:public Animal(string name,int age)this.name=name;this.age=age;l则编译时如出现则编译时如出现“Animal不包含采用不包含采用0个参数的构造函数个参数的构造函数”的错误,这是因为当创建派生类对象时,系统默认调用基的错误,这是因为当创建派生类对象时,系统
16、默认调用基类的默认构造函数(即无参构造函数),而当基类没有默类的默认构造函数(即无参构造函数),而当基类没有默认构造函数或想调用基类的带参的构造函数时,需要使用认构造函数或想调用基类的带参的构造函数时,需要使用base关键字。其格式如下:关键字。其格式如下:lpublic 派生类构造函数名派生类构造函数名(形参列表形参列表):base(向基类构造函向基类构造函数传递的形参列表数传递的形参列表)5.2.1 类的继承性类的继承性l【实例实例5-3】调用基类带参构造函数演示。调用基类带参构造函数演示。5.2.1 类的继承性类的继承性l3密封类密封类l为了阻止一个类的代码被其他类继承,可以使用密封类,
17、为了阻止一个类的代码被其他类继承,可以使用密封类,因为在因为在.NET中,加载密封类时将对密封类的方法调用进行中,加载密封类时将对密封类的方法调用进行优化,因此使用密封类可以提高应用程序的可靠性和性能。优化,因此使用密封类可以提高应用程序的可靠性和性能。另外,软件开发者通过使用密封类还可以把自己的知识产另外,软件开发者通过使用密封类还可以把自己的知识产权保护起来,避免他人共享代码。权保护起来,避免他人共享代码。l在在C#中,添加关键字中,添加关键字sealed可以声明密封类。可以声明密封类。5.2.2 类的多态性类的多态性l多态性是面向对象程序设计的一个重要特征,多态的意思多态性是面向对象程序
18、设计的一个重要特征,多态的意思是一种事物有多种形态。是一种事物有多种形态。l当派生类从基类继承时,它会获得基类的所有方法、字段、当派生类从基类继承时,它会获得基类的所有方法、字段、属性和事件。派生类允许扩展基类的成员,也可以重写基属性和事件。派生类允许扩展基类的成员,也可以重写基类的方法成员,以更改基类的数据和行为。为了使用派生类的方法成员,以更改基类的数据和行为。为了使用派生类能更改基类的数据和行为,类能更改基类的数据和行为,C#提供了两种选择:一是使提供了两种选择:一是使用新的派生成员替换基成员,二是重写虚拟的基成员。用新的派生成员替换基成员,二是重写虚拟的基成员。l在在C#中,基类对象可
19、以引用派生类对象,但不允许派生类中,基类对象可以引用派生类对象,但不允许派生类对象引用基类对象,这样,一个基类对象名称既可以指向对象引用基类对象,这样,一个基类对象名称既可以指向基类对象,也可以指向派生对象。而当基类对象执行一个基类对象,也可以指向派生对象。而当基类对象执行一个基类与派生类都具有的同名方法调用时,程序可以根据基基类与派生类都具有的同名方法调用时,程序可以根据基类对象的类型不同(基类还是派生类)进行正确的调用。类对象的类型不同(基类还是派生类)进行正确的调用。5.2.2 类的多态性类的多态性l1使用使用new关键字重新定义类的成员关键字重新定义类的成员 使用使用new关键字来定义
20、与基类中同名的成员,即可替换基类关键字来定义与基类中同名的成员,即可替换基类的成员。如果基类定义了一个方法、字段或属性,则的成员。如果基类定义了一个方法、字段或属性,则new关键字用于在派生类中创建该方法、字段或属性的新定义。关键字用于在派生类中创建该方法、字段或属性的新定义。new关键字应放置在要替换的类成员的返回类型之前。关键字应放置在要替换的类成员的返回类型之前。l2用用virtual和和override关键字定义类成员关键字定义类成员 基类中的声明格式:基类中的声明格式:public virtual 方法名称方法名称(参数列表参数列表)派生类的声明格式:派生类的声明格式:public
21、override方法名称方法名称(参数列表参数列表)l其中,基类与派生类中的方法名称与参数列表必须完全一其中,基类与派生类中的方法名称与参数列表必须完全一致致。5.2.2 类的多态性类的多态性l【实例实例5-4】虚方法演示。虚方法演示。5.2.2 类的多态性类的多态性l当点击当点击“创建子类对象并调用方法创建子类对象并调用方法”按钮时,以子按钮时,以子类对象做为实参,将调用子类的类对象做为实参,将调用子类的Eat方法,显示结方法,显示结果会不同果会不同5.2.2 类的多态性类的多态性l使用使用virtual和和override时要注意以下几点:时要注意以下几点:l(1)字段不能是虚拟的,只有方
22、法、属性、事件和索引器才字段不能是虚拟的,只有方法、属性、事件和索引器才可以是虚拟的;可以是虚拟的;l(2)使用使用virtual修饰符后,不允许再使用修饰符后,不允许再使用static、abstract或或override修饰符;修饰符;l(3)派生类对象即使被强制转换为基类对象,所引用的仍然派生类对象即使被强制转换为基类对象,所引用的仍然是派生类的成员;是派生类的成员;l(4)派生类可以通过密封来停止虚拟继承,此时派生类的成派生类可以通过密封来停止虚拟继承,此时派生类的成员使用员使用sealed override声明。声明。5.2.2 类的多态性类的多态性l3调用基类方法调用基类方法l当派
23、生类重载或覆盖基类方法后,如果想调用基类的同名当派生类重载或覆盖基类方法后,如果想调用基类的同名方法,可以使用方法,可以使用base关键字。如,在关键字。如,在Dog类的类的Eat方法中,方法中,希望使用基类的希望使用基类的Eat方法,可以用如下方法:方法,可以用如下方法:lpublic override void Eat()l l base.Eat();l5.3 抽象类与接口抽象类与接口l5.3.1 抽象类抽象类l5.3.2 接口接口l5.3.3 抽象类与接口的比较抽象类与接口的比较返回返回5.3.1 抽象类抽象类l抽象方法是指在基类的定义中,不包含任何实现代码的方抽象方法是指在基类的定义中
24、,不包含任何实现代码的方法,实际上就是一个不具有任何具体功能的方法。这样的法,实际上就是一个不具有任何具体功能的方法。这样的方法唯一的作用就是让派生类重写。方法唯一的作用就是让派生类重写。l而只要在类中包含一个抽象方法,该类即为抽象类。在抽而只要在类中包含一个抽象方法,该类即为抽象类。在抽象类中,也可以声明非抽象方法。象类中,也可以声明非抽象方法。1抽象类与抽象方法的声明抽象类与抽象方法的声明 在在C#中,抽象类和抽象方法使用关键字中,抽象类和抽象方法使用关键字abstract声明,一般声明,一般形式如下:形式如下:public abstract class 抽象类名抽象类名 访问修饰符访问修
25、饰符 abstract 返回值类型返回值类型 方法名(方法名(参数列表参数列表)5.3.1 抽象类抽象类l抽象类中也可以有抽象属性。类的属性成员添加了抽象类中也可以有抽象属性。类的属性成员添加了abstract关键字后,就成了抽象属性。抽象属性不提供属关键字后,就成了抽象属性。抽象属性不提供属性访问器的实现,它只声明该类支持的属性,而将访问器性访问器的实现,它只声明该类支持的属性,而将访问器的实现留给派生类。抽象属性同样可以是只读的、只写的的实现留给派生类。抽象属性同样可以是只读的、只写的或可读写的属性。一般形式如下:或可读写的属性。一般形式如下:public abstract返回值类型返回值
26、类型 属性名属性名 get;set;l抽象类可以包含抽象的成员,如抽象属性和抽象方法,也抽象类可以包含抽象的成员,如抽象属性和抽象方法,也可以包含非抽象的成员,甚至还可以包含虚方法。要注意可以包含非抽象的成员,甚至还可以包含虚方法。要注意的是,抽象成员必须在抽象类中声明,但抽象类不要求必的是,抽象成员必须在抽象类中声明,但抽象类不要求必须包含抽象成员须包含抽象成员5.3.1 抽象类抽象类l2重载抽象方法重载抽象方法l抽象类中的抽象方法和抽象属性都没有提供实现,当定义抽象类中的抽象方法和抽象属性都没有提供实现,当定义抽象类的派生类时,派生类必须重载基类的抽象方法和抽抽象类的派生类时,派生类必须重
27、载基类的抽象方法和抽象属性(如果派生类没有进行重载,则派生也必须声明为象属性(如果派生类没有进行重载,则派生也必须声明为抽象类,即在类定义前加上抽象类,即在类定义前加上abstract。这一点是与虚方法。这一点是与虚方法不同的,因为对于基类的虚方法,其派生类可以不重载。不同的,因为对于基类的虚方法,其派生类可以不重载。重载抽象类的方法和属性必须使用重载抽象类的方法和属性必须使用override关键字。重载关键字。重载抽象方法的格式为:抽象方法的格式为:lpublic override方法名称方法名称(参数列表参数列表)l其中,方法名称和参数列表必须与抽象类中的抽象方法完其中,方法名称和参数列表
28、必须与抽象类中的抽象方法完全一致。全一致。5.3.1 抽象类抽象类l【实例实例5-5】抽象方法和抽象类演示。抽象方法和抽象类演示。5.3.2 接口接口l接口接口(interface)是是C#的一种数据类型,属于引用类型。一的一种数据类型,属于引用类型。一个接口定义一个协定。接口可以包含方法、属性、事件和个接口定义一个协定。接口可以包含方法、属性、事件和索引器,接口本身不提供它所定义的成员的实现,接口只索引器,接口本身不提供它所定义的成员的实现,接口只指定实现该接口的类或结构必须提供的成员。实现某接口指定实现该接口的类或结构必须提供的成员。实现某接口的类必须遵守该接口定义的协定,即必须提供接口成
29、员的的类必须遵守该接口定义的协定,即必须提供接口成员的实现。实现。l1接口的声明接口的声明l在在C#中,声明接口使用中,声明接口使用interface关键字,一般形式如下:关键字,一般形式如下:访问修饰符访问修饰符 interface 接口名接口名:基接口列表基接口列表 /接口成员接口成员 5.3.2 接口接口l接口成员可以是属性、方法、索引器和事件,不能包含字接口成员可以是属性、方法、索引器和事件,不能包含字段、构造函数等。所有接口成员隐式地具有了段、构造函数等。所有接口成员隐式地具有了public访问访问修饰符,因此,接口成员不能添加任何访问修饰符。下面修饰符,因此,接口成员不能添加任何访
30、问修饰符。下面示例定义了一个示例定义了一个USB的接口,该接口包含了一个的接口,该接口包含了一个TransData方法签名和一个获到最大传输速率的只读属性。方法签名和一个获到最大传输速率的只读属性。interface IUsb int MaxSpeed get;string TransData(string from,string to);5.3.2 接口接口l2接口的实现接口的实现l接口主要用来定义一个规则,让企业内部或行业内部的软接口主要用来定义一个规则,让企业内部或行业内部的软件开发人员按标准去实现应用程序的功能。因此,继承接件开发人员按标准去实现应用程序的功能。因此,继承接口的类或结构
31、必须实现接口中的所有属性、方法、索引器口的类或结构必须实现接口中的所有属性、方法、索引器和事件,继承接口的方法与继承类相似和事件,继承接口的方法与继承类相似 l3接口的继承接口的继承l接口也可以继承其它接口,而接口可以多继承,即接口可接口也可以继承其它接口,而接口可以多继承,即接口可以从多个接口继承,基接口名之间用逗号分隔。以从多个接口继承,基接口名之间用逗号分隔。5.3.2 接口接口l4多重接口实现多重接口实现lC#不允许多重类继承,但是不允许多重类继承,但是C#允许多重接口实现,这意味允许多重接口实现,这意味着一个类可以实现多个接口,如果一个着一个类可以实现多个接口,如果一个Mobile类
32、支持类支持USB,也可以支持,也可以支持Bluetooth,我们就应该同时实现,我们就应该同时实现IUsb和和IBluetooth接口,在继承时,两个接口之间用逗号分隔。接口,在继承时,两个接口之间用逗号分隔。其类的头部如下所示:其类的头部如下所示:public class Mobile:IUsb,IBluetoothl如果类如果类Mobile是类是类phone的派生子类,也可以同时继承的派生子类,也可以同时继承phone类。但要注意,基类必须在所有的接口之前,如:类。但要注意,基类必须在所有的接口之前,如:public class Mobile:Phone,IUsb,IBluetooth5.
33、3.2 接口接口l5访问接口的方法访问接口的方法l当类当类Mp3实现了实现了IUsb后,我们可以通过后,我们可以通过MP3类的对象访问类的对象访问IUsb的成员,就好象是的成员,就好象是Mp3类的成员一样:类的成员一样:Mp3 m=new Mp3();lblShow.Text=m.TransData(计算机计算机,MP3设备设备);l或者我们也可以将或者我们也可以将Mp3对象转换成接口类型,然后用这个对象转换成接口类型,然后用这个接口来访问方法:接口来访问方法:Mp3 m=new Mp3();IUsb iu=(IUsb)m;lblShow.Text=iu.TransData(计算机计算机,MP
34、3设备设备);5.3.2 接口接口l【实例实例5-6】接口演示。接口演示。5.3.3 抽象类与接口的比较抽象类与接口的比较l抽象类是一种不能实例化的类,抽象类可以包含抽象成员,抽象类是一种不能实例化的类,抽象类可以包含抽象成员,也可以包含非抽象成员,即抽象类可以是完全实现的,也也可以包含非抽象成员,即抽象类可以是完全实现的,也可以是部分实现的,或者完全不实现的。抽象类可以用来可以是部分实现的,或者完全不实现的。抽象类可以用来封装所有派生类的通用功能。封装所有派生类的通用功能。l与抽象类不同的是,接口顶多像一个完全没有实现的只包与抽象类不同的是,接口顶多像一个完全没有实现的只包含抽象成员的抽象类
35、,因此无法使用接口来封装所有派生含抽象成员的抽象类,因此无法使用接口来封装所有派生类的通用功能,接口更多地用来制定程序设计开发规范,类的通用功能,接口更多地用来制定程序设计开发规范,接口的代码实现由开发者完成。例如,有关接口的代码实现由开发者完成。例如,有关XML文档的处文档的处理,万维网联盟(理,万维网联盟(W3C)就制定了一个)就制定了一个DOM(文档对象模(文档对象模型)规范,而具体的代码实现由诸如型)规范,而具体的代码实现由诸如Microsoft、Sun等公等公司去实现。司去实现。5.3.3 抽象类与接口的比较抽象类与接口的比较lC#规定一个类只能从一个基类派生,但允许从多个接口派规定
36、一个类只能从一个基类派生,但允许从多个接口派生。例如,如果把实例生。例如,如果把实例5-6中的两个接口改为抽象类,则不中的两个接口改为抽象类,则不允许同时使用它们来派生允许同时使用它们来派生Mobile类。类。l抽象类为管理组件版本提供了一个简单易行的方法。通过抽象类为管理组件版本提供了一个简单易行的方法。通过更新基类,所有派生类都将自动进行相应改动。而接口在更新基类,所有派生类都将自动进行相应改动。而接口在创建后就不能再更改,如果需要修改接口,必须创建新的创建后就不能再更改,如果需要修改接口,必须创建新的接口。接口。5.4 嵌套类、分部类与命名空间嵌套类、分部类与命名空间l5.4.1 嵌套类
37、嵌套类l5.4.2 分部类分部类l5.4.3 命名空间命名空间返回返回5.4.1 嵌套类嵌套类l在类的内部或结构的内部定义的类型称为嵌套类型,又称在类的内部或结构的内部定义的类型称为嵌套类型,又称内部类型。不论是类还是结构,嵌套类型均默认为内部类型。不论是类还是结构,嵌套类型均默认为private,嵌套类型也可以设置为,嵌套类型也可以设置为public、internal、protected或或protected internal。嵌套类型通常需要实例化为对象之后,。嵌套类型通常需要实例化为对象之后,才能引用其成员,其使用方法与类的普通成员使用基本相才能引用其成员,其使用方法与类的普通成员使用基
38、本相同。同。l【实例实例5-7】使用嵌套类计算长方形面积。使用嵌套类计算长方形面积。5.4.2 分部类分部类l分部类允许将类、结构或接口的定义拆分到两个或多个源分部类允许将类、结构或接口的定义拆分到两个或多个源文件中,让每个源文件只包含类型定义的一部分,编译时文件中,让每个源文件只包含类型定义的一部分,编译时编译器自动把所有部分组合起来进行编译。编译器自动把所有部分组合起来进行编译。l有了分部类,一个类的源代码可以分布于多个独立文件中,有了分部类,一个类的源代码可以分布于多个独立文件中,在处理大型项目时,过去很多只能由一个人进行的编程任在处理大型项目时,过去很多只能由一个人进行的编程任务,现在
39、可以由多个人同时进行,这样将大大加快了程序务,现在可以由多个人同时进行,这样将大大加快了程序设计的工作进度。设计的工作进度。l有了分部类,使用自动生成的源代码时,无需重新创建源有了分部类,使用自动生成的源代码时,无需重新创建源文件便可将代码添加到类中。事实上,当创建文件便可将代码添加到类中。事实上,当创建Windows应应用程序或用程序或Web应用程序时,就是在应用程序时,就是在Visual Studio 2010自自动生成源代码的基础之上专注于项目的业务处理,编译时动生成源代码的基础之上专注于项目的业务处理,编译时Visual Studio 2010会自动把编写的代码与自动生成的代会自动把编
40、写的代码与自动生成的代码进行合并编译。码进行合并编译。5.4.2 分部类分部类l处理分部类的定义时需遵循以下几个规则:处理分部类的定义时需遵循以下几个规则:l(1)同一类型的各个部分的所有分部类的定义都必须使用同一类型的各个部分的所有分部类的定义都必须使用partial进行修饰。进行修饰。l(2)如果将任意部分声明为抽象的,则整个类型都被视为抽如果将任意部分声明为抽象的,则整个类型都被视为抽象的。如果将任意部分声明为密封的,则整个类型都被视象的。如果将任意部分声明为密封的,则整个类型都被视为密封的。为密封的。l(3)partial修饰符只能出现在紧靠关键字修饰符只能出现在紧靠关键字class、
41、struct或或interface前面的位置。前面的位置。l(4)分部类的各部分或者各个源文件都可以独立引用类库,分部类的各部分或者各个源文件都可以独立引用类库,且坚持且坚持“谁使用谁负责添加引用谁使用谁负责添加引用”的原则。例如,上例中的原则。例如,上例中Test1.cs没有使用类库,则不添加类库的引用,而没有使用类库,则不添加类库的引用,而Test2.cs调用了方法调用了方法Console.WriteLine,则必须使用,则必须使用using System以添加系统类库的引用。以添加系统类库的引用。l(5)分部类的定义中允许使用嵌套的分部类分部类的定义中允许使用嵌套的分部类 5.4.3 命
42、名空间命名空间l对于一个大型软件项目来说,当多个程序员共同参与开发对于一个大型软件项目来说,当多个程序员共同参与开发时,因为这些程序员可能以同样的名字来创建类。命名空时,因为这些程序员可能以同样的名字来创建类。命名空间可将相互关联的类组织起来,形成一个逻辑上相关联的间可将相互关联的类组织起来,形成一个逻辑上相关联的层次结构,命名空间既可以对内组织应用程序,也可对外层次结构,命名空间既可以对内组织应用程序,也可对外避免命名冲突。避免命名冲突。l1.NET Framework的常用命名空间的常用命名空间l.NET Framework是由许多命名空间组成的,是由许多命名空间组成的,.NET就是利就是
43、利用这些命名空间来管理庞大的类库。例如,命名空间用这些命名空间来管理庞大的类库。例如,命名空间System.Web.UI.WebControls就提供了用来创建就提供了用来创建Web网网页的所有可用类,包括文本框(页的所有可用类,包括文本框(TextBox)、命令按钮)、命令按钮(Button)、标签()、标签(Lable)和列表框()和列表框(ListBox)等;而)等;而System.Windows.Forms则提供了用于创建基于则提供了用于创建基于 Windows 的应用程序的所有可用类,同样包括文本框、命的应用程序的所有可用类,同样包括文本框、命令按钮和标签等。令按钮和标签等。5.4.
44、3 命名空间命名空间l2自定义命名空间自定义命名空间l在在C#程序中,使用关键字程序中,使用关键字namespace就可以定义自己的就可以定义自己的命名空间,一般形式如下:命名空间,一般形式如下:namespace 命名空间名命名空间名 /类型的声明类型的声明 l其中,命名空间名必须遵守其中,命名空间名必须遵守C#的命名规范,命名空间内一的命名规范,命名空间内一般由若干个类型组成,例如声明枚举型、结构型、接口和般由若干个类型组成,例如声明枚举型、结构型、接口和类等类等 5.4.3 命名空间命名空间l3引用命名空间中的类引用命名空间中的类l引用命名空间中的类有两种方法:一是采用完全限定名来引用命
45、名空间中的类有两种方法:一是采用完全限定名来引用,例如:引用,例如:CompanyName.Sales.Customer cust=new CompanyName.Sales.Customer();l二是首先通过二是首先通过using关键字导入命名空间,再直接引用。就关键字导入命名空间,再直接引用。就是通过完全限定名来引用命名空间是通过完全限定名来引用命名空间CompanyName.Sales,并使用该命名空间中,并使用该命名空间中Customer类的构造函数创建一个新类的构造函数创建一个新对象,例如:对象,例如:using CompanyName.Sales;Customer cust=new Customer();l也就是先通过也就是先通过using关键字导入命名空间,再直接引用。关键字导入命名空间,再直接引用。2023/4/248作业作业l l1.书面作业(见本章教材)书面作业(见本章教材)l l2.上机实验(见本章教材)上机实验(见本章教材)2023/4/249Class OverThank you!
限制150内