




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
本章主要介绍面向对象的一些高级概念以及C#语言与其它面向对象语言的区别。重点介绍C#语言的属性与索引器、继承、抽象类、接口、托管、事件和类型运算。
3.1属性与索引器在C#中提供了一些很有用的功能,例如,属性、索引器、托管等,这些功能Java和C++都没有而且使用起来也非常方便。 属性实际上是设置字段和获取字段值的简单方法。其定义格式如表3.1所示。表中的get和set语句块,它们分别完成字段的获取和设置。第3章面向对象的高级概念
表3.1属性格式定义定义属性格式例子修饰符返回类型属性名{get{语句集合}Set{语句集合}}public
string
名称{get
{return
名称;}set
{名称=value;}}索引器实际上是设置表元数或集合元数和获取表元数或集合元数值的简单方法。其定义格式如表3.2所示。表中的get和set语句块,它们分别完成表元数或集合元数的获取和设置。定义索引器格式例子修饰符返回类型this[参数表]{get{语句集合}Set{语句集合}}public
计算机
this[intn]{//位置n原来没有计算机,现在加一台。set{if(计算机集合[n]==null)计算机数量++;//位置n原来有计算机,现在置为空if(value==null&&计算机集合[n]!=null)
计算机数量--;
计算机集合[n]=value;}get{return
计算机集合[n];}}属性和索引器.cs:usingSystem;namespaceTestSpace{publicclass计算机
{privatestring_名称;privatedouble_价格;privatestring_类型;//声明属性
publicstring名称
{get{return_名称;}set{_名称=value;}}publicdouble价格
{get{return_价格;}set{_价格=value;}}
publicstring类型
{get{return_类型;}set{_类型=value;}}//构造器
public计算机(stringn,doublep,stringt){名称=n;价格=p;类型=t;}}publicclass商城
{private计算机[]计算机集合=new计算机[10000];privateint计算机数量=0;publicint数量{get{return计算机数量;}}//返回当前计算机数量//索引器
public计算机this[string计算机名称]{get{//按计算机名称返回计算机对象
foreach(计算机Jin计算机集合)if(J.名称==计算机名称)returnJ;returnnull;}}public计算机this[string计算机名称,string类型]{get{//按计算机名称和类型返回计算机对象
foreach(计算机Jin计算机集合)if(J.名称==计算机名称&&J.类型==类型)returnJ;returnnull;}}
public计算机this[intn]{set{//如果是商店里没有此计算机则计算机数量增加
if(计算机集合[n]==null)计算机数量++;if(value==null&&计算机集合[n]!=null)
计算机数量--;
计算机集合[n]=value;}get{return计算机集合[n];}}}classTest{[STAThread]staticvoidMain(string[]args){
商城我的店=new商城();
计算机计算机1=new计算机("联想扬天",3100,"T5900VAX2215");
计算机计算机2=new计算机("IBMThinkPad",5700,"E400578A46");
我的店[我的店.数量]=计算机1; //调用索引器赋值我的店[我的店.数量]=计算机2; //调用索引器赋值计算机a=我的店["联想扬天"]; //调用索引器按名称获得计算机计算机b=我的店["IBMThinkPad","E400578A46"]; //调用索引器按类型和名称获得计算机
Console.WriteLine("名称:{0}{1},价格:{2}",a.名称,a.类型,a.价格);//用属性显示计算机内容
Console.WriteLine("名称:{0}{1},价格:{2}",b.名称,b.类型,b.价格);}}} 3.2继承继承是面向对象语言的主要特点,概念和意义大家都已经熟悉。这里主要想介绍一下C#的继承和其他语言的区别和特点,并给出一个应用实例。继承可以分为单继承和多继承或者分为直接继承和间接继承。设A、B、C是3个独立的类,图3.1分别可以表示:a单继承;b多继承;c直接继承;d间接继承等。
图3.1类的继承图左边为:单继承(B继承A)、直接继承(B直接继承A)和间接继承(C间接继承A);中间为:多继承;右边为:继承到多个类;要注意的是:C#不能为多继承。下面给出一个现实生活中最容易理解的例子“继承.CS”。ABCACBABCusingSystem;namespaceTest{class爷爷
{protectedstring房子="房子";publicvoid盖房(){Console.WriteLine("爷爷盖房子");}}class父亲:爷爷
{protectedstring车子="车子";publicvoid开车(){Console.WriteLine("父亲开车");}}class本人:父亲
{protectedstring儿子="儿子";publicvoid教书(){Console.WriteLine("本人教书");}publicvoid有(){Console.WriteLine("我有:爷爷的{0},父亲的{1},我的{2}",房子,车子,儿子);}publicstatic本人叫儿子(){returnnew儿子();}}class儿子:本人
{protectedstring专业="工业设计";publicvoid设计动漫(){Console.WriteLine("儿子设计动漫");}}classProgram{publicstaticvoidMain(string[]args){
本人我本人=new本人();
我本人.有();
我本人.盖房();
我本人.开车();
我本人.教书();
本人我=本人.叫儿子();
我.有();
我.盖房();
我.开车();
我.教书();((儿子)我).设计动漫();((爷爷)我本人).盖房();((父亲)我本人).开车();}}}在类继承中需要注意的问题是:1Base和this的使用。Base表示对基类(父类)的构造方法的调用,this表示当前对象。更进一步的了解见程序:Base和this.CS。2子类对象可以使用父类对象的成员和方法,而父类对象则不能使用子类对象的成员和方法。例如,继承.CS中,可以使用:((父亲)我本人).开车();而不能使用:((儿子)我本人).设计动漫();usingSystem;namespaceTest{publicclass人
{privatestring电话;privatestring名字;publicstring获得名字{get{return名字;}}publicstring获得电话{get{return电话;}}public人(string_名字){
名字=_名字;}public人(string_名字,string_电话){
电话=_电话;
名字=_名字;}}
class职工:人
{publicstring职工号="ABC567EFG";public职工(string名字,string电话,string工号):base(名字,电话){
职工号=工号;}publicvoid显示职工(){Console.WriteLine("显示职工:名字={0};电话={1};职工号={2}",this.获得名字,this.获得电话,this.职工号);}}
classProgram{staticvoidMain(string[]args){职工e=new职工("李四","45999229","ABC567EFF");Console.WriteLine("名字:{0};电话:{1};职工号:{2}",e.获得名字,e.获得电话,e.职工号);e.显示职工();}}}
3.3类的关联关系关联关系
体现的是两个类之间语义级别的一种强依赖关系,这种关系比依赖更强、不存在依赖关系的偶然性、关系也不是临时性的,一般是长期性的,而且双方的关系一般是平等的。关联可以是单向、双向和自身。在UML类图设计中,关联关系用由关联类A指向被关联类B的带箭头实线表示,在关联的两端可以标注关联双方的角色和多重性标记。
3.3.1、关联
双向关联:
C1-C2:指双方都知道对方的存在,都可以调用对方的公共属性和方法。
虽然在分析阶段这种关系是适用的,但我们觉得它对于描述设计模式内的类关系来说显得太抽象了,因为在设计阶段关联关系必须被映射为对象引用或指针。对象引用本身就是有向的,更适合表达我们所讨论的那种关系。所以这种关系在设计的时候比较少用到,关联一般都是有向的。C1(类名)F(字段)M(方法)C2(类名)F2(字段)M2(方法)
使用C#生成的代码是这样的:class
C1
{
public
C2
theC2;};
class
C2
{
public
C1
theC1;};双向关联在代码的表现为双方都拥有对方的一个指针,当然也可以是引用或者是值。
单向关联:
C3->C4:表示相识关系,指C3知道C4,C3可以调用C4的公共属性和方法。一般是表示为一种引用。
C3C4
生成代码如下:class
C3
{
publicC4
theC4;};class
C4
{
……};单向关联的代码就表现为C3有C4的指针,而C4对C3一无所知。
自身关联
:
自己引用自己,带着一个自己的引用。
C4 C#代码如下:class
C14
{
public
C14
theC14;
};就是在自己的内部有着一个自身的引用。
3.3.2、聚合/组合
当类之间有整体-部分关系的时候,我们就可以使用组合或者聚合。
聚合:表示C7聚合C8,但是C8可以离开C7而独立存在(独立存在的意思是在某个应用的问题域中这个类的存在有意义。这句话怎么解,请看下面组合里的解释)。C7C8
生成代码如下:class
C7
{
public
C8
theC8;
};
class
C8{
};
组合:一般是实心菱形加实线箭头表示,如下图所示。表示的是C10被C9包容,而且C10不能离开C9而独立存在。但这是视问题域而定的,例如在关心汽车的领域里,轮胎是一定要组合在汽车类中的,因为它离开了汽车就没有意义了。但是在卖轮胎的店铺业务里,就算轮胎离开了汽车,它也是有意义的,这就可以用聚合了。
C9C10
生成代码如下:代码如下:class
C9
{
public
C10
theC10;
};
class
C10
{
};
可以看到,代码和聚合是一样的。具体如何区别,可能就只能用语义来区分了。
3.3.3、依赖
依赖:
指C5可能要用到C6的一些方法,也可以这样说,要完成C5里的所有功能,一定要有C6的方法协助才行。C5依赖于C6的定义。注意,要避免双向依赖。一般来说,不应该存在双向依赖。
C5C6……………
生成代码如下:UsingC6的命名空间ClassC5{
…..};ClassC5{
……Using{C6……};}
依赖和聚合\组合、关联等有什么不同呢?
关联是类之间的一种关系,例如老师教学生,这种关系是非常明显的,在问题领域中通过分析直接就能得出。
依赖是一种弱关联,只要一个类用到另一个类,但是和另一个类的关系不是太明显的时候(可以说是“uses”了那个类),就可以把这种关系看成是依赖,依赖也可说是一种偶然的关系,而不是必然的关系,就是“我在某个方法中偶然用到了它,但在现实中我和它并没多大关系”。例如我和粉笔,我和粉笔本来是没关系的,但在在黑板上写字的时候,我用到了它,这就是一种依赖,依赖粉笔完成这件事情。
组合是一种整体-部分的关系,在问题域中这种关系很明显,直接分析就可以得出的。例如轮胎是车的一部分,树叶是树的一部分,手脚是身体的一部分这种的关系,非常明显的整体-部分关系。
上述的几种关系(关联、聚合/组合、依赖)在代码中可能以指针、引用、值等的方式在另一个类中出现,不拘于形式,但在逻辑上他们就有以上的区别。
3.3.4泛化(继承)
泛化关系:如果两个类存在泛化的关系时就使用,例如父和子,动物和老虎,植物和花等。
C11C12 3.3.5类的多重性多重性说明了参与关联的对象的数目。多重性数值标注在每个关联端。多重性取值存在多重组合。下面是多种性取值的一些例子:1 恰好1个0:* 0个或多个1:* 1个或多个0:10个或1个3:9 3到9个
1:*0:*
1
有
1:*
多重性关联类图职员(类名)F1(字段)M1(方法)顾客(类名)F2(字段)M2(方法)订单(类名)F3(字段)M3(方法)
3.3.6抽象类抽象类实际上就是从事物中抽取其中的概念、本质和属性组成一个类,这些概念、本质和属性需要在它们的子类中去具体实现。故此抽象类不能实例化。抽象类定义格式如下:访问修饰abstractclass类名{
抽象类体}抽象类实现例子“抽象类.cs”。usingSystem;namespaceTest{publicabstractclass人
{publicabstractvoid显示();publicabstractstring名字{get;set;}publicabstractstringthis[intn]{get;set;}}publicclass职工:人
{privatestring姓名;publicoverridevoid显示(){Console.WriteLine("姓名:{0}",this.名字);}privatestring[]朋友=newstring[10];publicvoid显示朋友(){foreach(stringpin朋友)Console.WriteLine("朋友姓名:{0}",p);}}publicoverridestring名字
{get{returnthis.姓名;}set{this.姓名=value;}}publicoverridestringthis[intn]{get{returnthis.朋友[n];}set{this.朋友[n]=value;}}}
classProgram{staticvoidMain(string[]args){//人p=new职工();/*抽象类对象引用子类实例*/
职工e=new职工();e.名字="李先国";e[0]="张三";e[1]="李四";e[2]="王五";e.显示();e.显示朋友();
人p=(人)e;p.显示();}}}
3.4接口接口是一种允许多继承的类型,正好可以弥补C#不能多继承的缺陷。接口和抽象类的结合可以实现完整的继承体系。接口的定义格式如下:访问修饰interface接口名{接口内容}接口内容不能包含任何数据成员,可以是方法、属性和索引器成员,并且成员不能有访问修饰符,访问修饰符默认为public。简单的说,接口就是公共方法集的定义。它还可以由类来多继承。更仔细的学习参见例子“接口.CS”。usingSystem;namespaceTest{interface工作{void开车();void上课();}interface娱乐{void爬山();void吹笛子();
void打太极拳();}publicabstractclass人{publicabstractvoid显示();publicabstractstring名字{get;set;}publicabstractstringthis[intn]{get;set;}}publicclass职工:人,工作,娱乐{privatestring姓名;publicoverridevoid显示(){Console.WriteLine("姓名:{0}",this.名字);}privatestring[]朋友=newstring[10];publicvoid显示朋友(){
foreach(stringpin朋友)Console.WriteLine("朋友姓名:{0}",p);}
publicoverridestring名字{get{returnthis.姓名;}set{this.姓名=value;}}
publicoverridestringthis[intn]{get{returnthis.朋友[n];}set{this.朋友[n]=value;}}publicvoid开车(){Console.WriteLine("{0}正在开车",this.姓名);}publicvoid上课(){Console.WriteLine("{0}正在上课",this.姓名);}publicvoid爬山(){Console.WriteLine("{0}正在爬山",this.姓名);}publicvoid打太极拳(){Console.WriteLine("{0}正在打太极拳",this.姓名);}
publicvoid吹笛子(){Console.WriteLine("{0}正在吹笛子",this.姓名);}}classProgram{staticvoidMain(string[]args){//人p=new职工();/*抽象类对象引用子类实例*/职工e=new职工();e.名字="李先国";e[0]="张三";e[1]="李四";e[2]="王五";e.显示();e.开车();e.上课();e.爬山();e.吹笛子();e.打太极拳();}}}
3.5委托 委托本质上是一种类似类的类型,我们可以像建立一个类一样建立一个委托类型。委托类型可以定义委托变量,委托变量可以存放一个或多个方法,这些方法可以是对象的实例方法,也可以是类的静态方法。最后就可以使用该委托执行这些方法。委托类型的定义格式如下:[访问修饰符]delegate返回值类型委托类型名(参数表)
实际上,委托类型就是类似C语言的函数指针,但是一种类型安全的函数指针。我们可以将委托类型的定义格式中的delegate关键字去掉,把委托类型名看作函数名,就可以看到,它就是函数的定义头。多播委托是委托的一种特殊应用,多播委托允许在一个委托里添加多个方法并组成一条链,对链上的方法也可以进行+、-、+=和-=运算。详细应用见“委托和多播.cs”。
usingSystem;namespaceTest{interface工作
{void开车();void上课();}interface娱乐
{void爬山();void吹笛子();}publicabstractclass人
{publicabstractvoid显示();publicabstractstring名字{get;set;}publicabstractstringthis[intn]{get;set;}}
publicvoid开车(){Console.WriteLine("{0}正在开车",this.姓名);}publicvoid上课(){Console.WriteLine("{0}正在上课",this.姓名);}publicvoid爬山(){Console.WriteLine("{0}正在爬山",this.姓名);}publicvoid吹笛子(){Console.WriteLine("{0}正在吹笛子",this.姓名);}}publicclass职工:人,工作,娱乐
{privatestring姓名;publicoverridevoid显示(){Console.WriteLine("姓名:{0}",this.名字);}privatestring[]朋友=newstring[10];publicvoid显示朋友(){foreach(stringpin朋友)Console.WriteLine("朋友姓名:{0}",p);}
publicoverridestring名字
{get{returnthis.姓名;}set{this.姓名=value;}}publicoverridestringthis[intn]{get{returnthis.朋友[n];}set{this.朋友[n]=value;}}
class计算面积
{publicstaticvoid园面积(doubleVal){Console.WriteLine("半径={0},园面积="+Val*Val*3.1416,Val);}publicstaticvoid正方形面积(doubleVal){Console.WriteLine("边长={0},正方形面积="+Val*Val,Val);}}class多播委托
{publicdelegatevoid多播委托职工();publicdelegatevoid多播委托面积计算(doubled);staticvoidMain(string[]args)
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
评论
0/150
提交评论