C網絡編程技術教程_第1頁
C網絡編程技術教程_第2頁
C網絡編程技術教程_第3頁
C網絡編程技術教程_第4頁
C網絡編程技術教程_第5頁
已閱讀5頁,還剩101頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

C#網絡編程技術教程第三章C#面向對象編程

docin/sundae_mengC#網絡編程技術教程第三章C#面向對象編程docin/學習目標理解面向對象的基本概念。了解基本的面向對象分析、設計方法,主要是UML中的類圖和序列圖。掌握C#中類的定義和實例化方法。掌握C#中繼承、多態(tài)、接口的實現方法。學習目標理解面向對象的基本概念。本章內容3.1面向對象的基本概念3.2類和對象3.3字段3.4方法3.5屬性與索引3.6委托與事件3.7繼承與多態(tài)3.8基于UML的系統(tǒng)分析與設計方法本章內容3.1面向對象的基本概念3.1面向對象的基本概念

客觀世界是由各種各樣的對象組成的,如汽車、飛機、火車、人等。每種對象都有各自的內部狀態(tài)和運動規(guī)律,不同對象之間的相互作用和聯系就構成了各種不同的系統(tǒng)。將客觀世界中的對象模型化,形成一種計算機化的表示,并以此為基礎來分析和解決問題便形成了面向對象技術。PeterCoad和EdwardYourdon提出了下列等式來說明面向對象技術。面向對象=對象+分類+繼承+消息通信可以說,采用對象、類、繼承、消息這4個概念開發(fā)的軟件系統(tǒng)是面向對象的。3.1面向對象的基本概念客觀世界是由各種3.1面向對象的基本概念1.對象在面向對象技術中,任何客觀事物都是對象,對象是對客觀事物的抽象。任何復雜的事物都可以通過對象的某種組合結構構成。復雜對象可由相對比較簡單的對象以某種方式組成。對象由屬性和方法組成。屬性反映了對象的信息特征,而方法則定義改變屬性狀態(tài)的各種操作。因此,對象是屬性和方法的一個封裝體。通過封裝可以更好地隱蔽對象的內部細節(jié),只保留有限的對外接口實現對外聯系。每個對象都有自身唯一的標識,通過這種標識,可找到相應的對象。在對象的整個生命期中,它的標識都不改變,不同的對象不能有相同的標識。2.類具有相同屬性和方法的對象可歸納成類,對象是類的一個實例,而對象的抽象是類。類具有屬性,它是對象的狀態(tài)的抽象,用數據結構來描述類的屬性;類具有操作,它是對象的行為的抽象,用操作名和實現該操作的方法來描述。3.1面向對象的基本概念1.對象3.1面向對象的基本概念3.繼承類有一定的結構,可以派生出子類,子類除了繼承父類的屬性和方法外還可以有自己的屬性和方法。對象和類之間的層次結構靠繼承關系維系。繼承是子類自動共享父類數據結構和方法的機制,也是面向對象程序設計語言不同于其他語言的最重要的特點。在類層次中,將子類只繼承一個父類的數據結構和方法的方式稱為單重繼承;將子類繼承多個父類的數據結構和方法的方式稱為多重繼承。在軟件開發(fā)中,類的繼承使所建立的軟件具有開放性、可擴充性,這是信息組織與分類的行之有效的方法,它簡化了對象、類的創(chuàng)建工作量,增加了代碼的重用性。同時,通過類的繼承關系,使公共的特性能夠共享,提高了軟件的重用性。4.消息對象之間的聯系主要是通過傳遞消息來實現,消息傳遞是對象間通信的手段,一個對象通過向另一個對象發(fā)送消息來請求其服務。一個消息通常包含接收對象的標識、發(fā)送給接收對象的消息名(方法名)和適當的參數。消息只告訴接收對象需要完成什么操作,但并不指示接收者如何完成操作。消息完全由接收者解釋,并由其獨立決定采用什么方法完成所需的操作。3.1面向對象的基本概念3.繼承3.1面向對象的基本概念5.多態(tài)性多態(tài)性是指相同的操作或方法可作用于多種類型的對象上并獲得不同的結果。即將不同的對象收到同一消息時產生不同的結果的現象稱為多態(tài)性。多態(tài)性允許每個對象以適合自身的方式去響應共同的消息,增強了軟件的靈活性和重用性。面向對象技術正是利用對現實世界中對象的抽象和對象之間的相互關聯和相互作用的描述來模擬現實世界,并且使其映射到目標系統(tǒng)中。3.1面向對象的基本概念5.多態(tài)性3.2類和對象

類是對象的抽象描述,類似于模板。從定義上來說,類是一種復雜的數據結構,其中包含數據成員和功能成員。在C#中,類必須先定義后使用。1.類的定義類是C#中最基礎的類型。類是一個數據結構,將數據成員(狀態(tài))和功能成員(行為)組合在一個單元中,進而體現了面向對象技術的封裝性。類的定義格式如下:Attribute類修飾符class類名[:基類和實現的接口列表]{

類成員定義}其中,類的修飾符如下表所示。修飾符描述none、internal類只能在當前項目中訪問public類可以在任何地方訪問abstract、internalabstract類只能在當前項目中訪問,且不能實例化,只能繼承publicabstract類可以在任何地方訪問,且不能實例化,只能繼承sealed、internalsealed類只能在當前項目中訪問,且只能實例化,不能繼承publicsealed類可以在任何地方訪問,且只能實例化,不能繼承3.2類和對象類是對象的抽象描述,類似于模3.2類和對象下面是一個名為Point的簡單類的聲明。publicclassPoint{privateintx,y;//數據成員

publicPoint(intx,inty){//功能成員

this.x=x;this.y=y;}}3.2類和對象下面是一個名為Point的簡單類的聲明。3.2類和對象2.類的成員類的成員分為數據成員和功能成員,其中數據成員包括:成員常量,代表與類相關的常數數據;字段,類的變量。功能成員包括:方法,即類中的成員函數;屬性,定義了命名的屬性以及讀寫屬性的相關的行為;索引,允許類的實例通過與數組相同的方法來索引;操作符,定義了可以用于類的實例上的表達式操作;事件,定義了由類產生的事件公告;構造函數,對類的實例進行初始化的操作;析構函數,在類的實例銷毀前執(zhí)行與資源釋放相關的操作。3.類成員的可訪問性類的每個成員都有關聯的可訪問性,它控制能夠訪問該成員的程序區(qū)域。在C#中,有5種可能的可訪問性,如下表所示??稍L問性描

述public訪問不受限制,定義的成員可以在類的外部訪問protected訪問僅限于包含類或從包含類派生的類internal訪問僅限于當前程序集(包)protectedinternal訪問僅限于從包含類派生的當前程序集(包)或類private訪問僅限于包含類3.2類和對象2.類的成員可訪問性描述pu3.2類和對象4.靜態(tài)成員和非靜態(tài)成員類的成員可以是靜態(tài)成員,也可以是非靜態(tài)成員。在C#中,用關鍵字static修飾的類成員(包括字段、方法、屬性、事件、操作符或構造函數)稱為靜態(tài)成員,它們屬于類。而沒有用關鍵字static修飾的類成員稱為非靜態(tài)成員,它們屬于對象。靜態(tài)成員具有如下特征。一個靜態(tài)字段對應一個存儲位置,不管其包含類創(chuàng)建了多少個實例,總是只有一個靜態(tài)字段的備份。靜態(tài)成員(包括方法、屬性、事件、操作符或構造函數)不會對非靜態(tài)成員進行操作,也不能使用this。靜態(tài)成員屬于類,因此可以在包含類的實例之間共享它們。靜態(tài)成員一般通過類來訪問,例如Console.ReadLine(

),其中ReadLine(

)就是類Console中的靜態(tài)方法。對于非靜態(tài)字段,在包含類的每個實例中都包括一個它的獨立備份,同時在非靜態(tài)成員中可以使用this,也可以對非靜態(tài)成員進行操作。非靜態(tài)成員通過包含類的實例來訪問。3.2類和對象4.靜態(tài)成員和非靜態(tài)成員3.2類和對象5.對象對象是類的實例。與C++不同,在C#中,類是一種引用類型,因此在C#中不能直接用類來定義對象,它定義的只是一個對象引用變量。一般可以使用new運算符動態(tài)創(chuàng)建一個對象,再將其賦值給一個對象引用變量。例如:Pointp1=newPoint(0,0);//指向一個動態(tài)創(chuàng)建的Point對象Pointp2=p1;//p1和p2指向同一個Point對象Pointp3;//不指向任何對象當不再使用對象時,該對象所占的內存將被自動回收。在C#中,沒有必要也不可能顯式地釋放對象。而是通過系統(tǒng)中的垃圾回收器來實現對無用對象的回收操作。6.構造函數與析構函數

C#既支持實例構造函數,也支持靜態(tài)構造函數。實例構造函數用來初始化類實例中的數據成員。靜態(tài)構造函數用來在類首次加載時初始化類本身的數據成員,即靜態(tài)字段。構造函數的名稱與類名相同,沒有返回類型。若構造函數的聲明中包含static修飾符,則它聲明了一個靜態(tài)構造函數,否則聲明的是實例構造函數。靜態(tài)構造函數不需要訪問修飾符,同時也不帶任何參數;實例構造函數可以帶參數表,可以加訪問修飾符進行修飾,不能被繼承。如果一個類沒有聲明任何實例構造函數,則會自動為它提供一個默認的空的實例構造函數,一般其參數列表為空,函數體也為空。3.2類和對象5.對象3.2類和對象

由于實例構造函數可以帶參數,因此實例構造函數可以重載,并且可以通過參數列表(參數的個數、類型和順序)來區(qū)分不同的實例構造函數。析構函數是用于實現析構類實例所需操作的成員。析構函數不能帶參數,不能具有可訪問性修飾符,也不能被顯式地調用。當沒有任何代碼要使用一個實例時,系統(tǒng)中的垃圾回收器會自動調用該實例的析構函數對其進行析構,如代碼實例所示。usingSystem;namespaceex_3_1{classProgram{privateintdata;//非靜態(tài)數據成員(字段)

staticprivateintstaticdata;//靜態(tài)數據成員

publicProgram(

)//無參數實例構造函數

{Console.WriteLine("無參數構造函數");data=0;}publicProgram(intvalue)//帶參數實例構造函數

{Console.WriteLine("帶參數構造函數");data=value;}staticProgram(

)//靜態(tài)構造函數

{Console.WriteLine("靜態(tài)構造函數");staticdata=100;}

~Program(

)//析構函數

{Console.WriteLine("析構函數");}publicvoidPrint(

)//打印方法

{Console.WriteLine("Staticdatais{0},Datais{1}",staticdata,data);}staticvoidMain(string[]args){Programp1;//沒有創(chuàng)建對象

Programp2=newProgram(

);//創(chuàng)建一個對象

Programp3=newProgram(50);//創(chuàng)建一個對象

p1=p3;p1.Print(

);p2.Print(

);p3.Print(

);}}}3.2類和對象由于實例構造函數可以帶參數,3.3字段

字段,即類的變量,類中的數據成員,用來存儲類所需的數據信息。它可以聲明為靜態(tài)的,也可以聲明為只讀的(readonly)。當字段被聲明為只讀時與聲明為const的效果是一樣的,區(qū)別在于只讀型表達式在程序運行時形成,而const型表達式的值在編譯時形成。只讀型字段可以通過構造函數賦值,但實例創(chuàng)建后則不能再對其進行賦值。字段聲明的格式如下:修飾符字段類型字段名列表;其中修飾符可以是public、protected、internal、private、static和readonly;字段類型可以是基本類型、用戶自定義類型和其他類。例如:classCalendarDate{publicreadonlyintmonth;//只讀字段,實例創(chuàng)建后不能對其賦值

publicintday;publicstaticintyear=2019;//靜態(tài)字段,屬于類的成員}

雖然字段是一種類變量,但是C#為每個未初始化的變量都確認一個默認值,因此字段聲明后便可以使用。這在一定程度上保證了程序的安全性。如下代碼實例所示為字段使用的程序實例。3.3字段字段,即類的變量,類中的數據成3.3字段usingSystem;namespaceex_3_2{classProgram{publicreadonlyintmonth;publicintday;publicstaticintyear=2019;publicProgram(

)//無參數的構造函數

{}publicProgram(intd,intm,inty)//構造函數中可以對只讀型字段賦值

{day=d;month=m;year=y;}publicvoidPrint(

){Console.WriteLine("Yearis{0},Monthis{1},Dayis{2}",year,month,day);}staticvoidMain(string[]args){Programp1=newProgram(10,10,2019);Programp2=newProgram(

);//字段具有默認值

p1.Print(

);p2.Print(

);p1.day=11;//p1.month=11;//錯誤,只讀型字段不能修改

p1.Print(

);}}}3.3字段usingSystem;3.4方法

方法是一種用于實現可以由對象或類執(zhí)行的計算或操作的功能成員。與C++中的函數成員類似,方法可以是靜態(tài)也可以是非靜態(tài)。靜態(tài)方法只能通過類來訪問,非靜態(tài)方法(即實例方法)則要通過類的實例訪問。方法有一個參數表(可能為空),表示傳遞給方法的值或者引用;方法還有返回類型,用于指定由該方法計算和返回的值的類型。如果方法不返回值,則它的返回類型為void。方法的聲明格式如下: 修飾符返回類型方法名稱(參數列表)

{

方法體

}

其中,方法的名稱、參數個數、參數順序、每個參數的修飾符和類型一起組成方法的簽名。在聲明方法的類中,該方法的簽名必須是唯一的。正因為方法可以帶參數,所以類中的方法可以重載,重載方法的簽名不同,主要是參數個數、參數類型和參數順序不同。3.4方法方法是一種用于實現可以由對3.4方法

在C#中,方法中的參數用于將值或者引用變量傳遞給方法體。當方法被調用時,方法的參數從指定的自變量得到它們實際的值。C#中有4種參數:值參數、引用參數、輸出參數和參量參數。值參數:用于輸入參數的傳遞。值參數相當于一個局部變量,它的初始值是從實參獲得的。對值參數的修改不會影響其對應的實參。引用參數:用于輸入和輸出數據的傳遞。引用參數對應的實參必須是一個變量,并且在方法執(zhí)行期間,引用參數和其實參指向同一個存儲空間,因此,引用參數值的變化將直接影響其實參。引用參數用ref修飾符聲明。輸出參數:用于輸出數據的傳遞。輸出參數類似于引用參數,不同之處在于實參有無初始值無關緊要。輸出參數用out修飾符聲明。參量參數:可以把一維數組或不規(guī)則數組傳遞給方法。在方法聲明的參數列表中,參量參數必須以params開始,例如:publicintsum(paramint[]intParams){方法體}。在帶參量參數的方法調用中,既可以傳遞數組類型的單個實參,也可以傳遞充當數組元素的若干實參。對于后一種的情形,數組實例將自動被創(chuàng)建,并且通過給定的實參初始化。3.4方法在C#中,方法中的參數用于3.4方法usingSystem;namespaceex_3_3{classFunc_Ex{staticprivateintobject_num=0;//靜態(tài)字段

publicintx,y,xy;privateintm_sum;publicFunc_Ex(inta,intb)//構造函數

{x=a;y=b;object_num++;//統(tǒng)計對象實例個數

}publicvoidswap(inta,intb)//值參數

{inttemp;temp=a;a=b;b=temp;}publicvoidswap(refinta,refintb,outints)//引用參數,輸出參數

{inttemp;temp=a;a=b;b=temp;

s=a+b;}publicvoidsum(paramsint[]intparams)//參量參數

{m_sum=0;foreach(intvinintparams)m_sum+=v;}publicvoidprint(

)//實例方法

{Console.WriteLine("x={0},y={1},xy={2},sum={3}",x,y,xy,m_sum);}staticpublicvoidprintObjectNum(

)//靜態(tài)方法

{Console.WriteLine("已創(chuàng)建的對象個數為{0}",object_num);}staticvoidMain(string[]args){Func_Exf1=newFunc_Ex(10,20);Func_Ex.printObjectNum(

);f1.print(

);//靜態(tài)方法調用

f1.swap(f1.x,f1.y);/*值參數的方法調用*/f1.print(

);f1.swap(reff1.x,reff1.y,outf1.xy);/*引用和輸出參數的方法調用*/f1.print(

);

Func_Exf2=newFunc_Ex(100,220);Func_Ex.printObjectNum(

);/*靜態(tài)方法調用*/f2.print(

);f2.sum(10,20,30,45);/*參量參數的方法調用*/f2.print(

);int[]a={1,3,5,7,9,11,23};f2.sum(a);/*參量參數的方法調用*/f2.print(

);

}}}3.4方法usingSystem;public3.5屬性與索引3.5.1屬性屬性是對對象或類的字段進行特定訪問的成員,是字段的自然擴展,并且訪問屬性和字段的語法相同。在C#中屬性與字段完全相同,屬性不表示存儲位置。而且屬性有訪問器,通過這些訪問器可以實現對相關字段值(或計算值)的訪問。在C#中,屬性的聲明格式如下:修飾符類型屬性名{get{

執(zhí)行代碼;

return表達式;

}set{

執(zhí)行代碼

}}get訪問器和set訪問器的功能如下。get訪問器相當于一個具有屬性類型返回值的無參數方法。當在表達式中引用屬性時,會調用該屬性的get訪問器來計算該屬性的值。set訪問器相當于一個具有單個名為value的參數和無返回類型的方法。當屬性作為賦值運算的左值表達式或者作為++或運算符的操作數被引用時,就會調用set訪問器來修改相應字段中的值。3.5屬性與索引3.5.1屬性3.5屬性與索引3.5.1屬性兩種訪問器都包含的屬性稱為讀寫屬性,只具有get訪問器的屬性稱為只讀屬性,只具有set訪問器的屬性稱為只寫屬性。與字段和方法類似,屬性可以被定義為實例屬性和靜態(tài)屬性。靜態(tài)屬性的聲明中具有static修飾符,而實例屬性則沒有,靜態(tài)屬性只能訪問靜態(tài)成員。屬性的訪問器可以是虛擬的。當屬性聲明中包含virtual、abstract、override修飾符時,它們將運用到屬性訪問器。但是,與字段或方法不完全相同,屬性聲明時需要注意如下幾點屬性不能聲明為const,也不能在一個表達式聲明多個屬性。不能通過set訪問器對屬性進行初始化。屬性不屬于變量,不能將屬性作為引用參數或輸出參數傳遞。屬性必須有返回類型,并且不能為void型。在屬性聲明中,除了get和set訪問器外,不能進行其他任何操作。3.5屬性與索引3.5.1屬性3.5屬性與索引3.5.2索引索引是這樣一個成員,它使對象能夠用與數組相同的方式進行索引。索引的聲明與屬性很相似,不同之處在于成員的名字是this,后面的參數列表在定界符“[]”之間。參數在索引的訪問器中是可用的。索引的聲明形式如下:修飾符類型this[類型index]{get{

執(zhí)行代碼;//主要是對index值指定的相應數組字段的某個元素進行訪問

return表達式;

}set{

執(zhí)行代碼;//主要是對index值指定的相應數組字段的某個元素進行訪問

}}

如果包含get和set訪問器,則該索引是讀寫索引;如果只包含get訪問器則是只讀索引;而只包含set訪問器則是只寫索引。注意:索引主要是用來通過數組下標的方式操作對象實例中的某個數組型字段成員的數組元素,而不是對象實例數組。3.5屬性與索引3.5.2索引3.5屬性與索引usingSystem;namespaceEx_3_4{classNameList{privatestring[]namelist;//名稱數組

privatereadonlyintMaxLength;//數組最大長度

privateintnamecount=0;//數組當前長度

staticprivateintnamelistcount=0;//實例個數

privatestringnamelisttile;//名稱標題字段

publicNameList(intmaxlength)//構造函數

{MaxLength=maxlength;namelist=newstring[MaxLength];namecount=0;namelistcount++;}staticpublicintNameListCount//靜態(tài)屬性

{get{returnnamelistcount;}}publicstringNameListTile//讀寫屬性

{get{returnnamelisttile;}set{namelisttile=value;}}publicintMAXLength//只讀屬性

{get{returnMaxLength;}}publicintCount//只讀屬性

{get{returnnamecount;}}publicstringthis[intindex]//讀寫索引

{get{if((index>=0)&&(index<namecount))returnnamelist[index];elsereturn"";}set{if((index>=0)&&(index<namecount))namelist[index]=value;}}publicvoidAddName(stringv)//方法

{if(namecount<MaxLength)namelist[namecount++]=v;}publicvoidPrintNamelist(

)//方法

{Console.WriteLine("NameListTileis{0}",namelisttile);for(inti=0;i<namecount;i++)Console.WriteLine("\tNamelist[{0}]is{1}",i,namelist[i]);}

3.5屬性與索引usingSystem;publi3.5屬性與索引staticvoidMain(string[]args)//測試代碼

{NameListnl1=newNameList(20);//創(chuàng)建兩個對象

NameListnl2=newNameList(10);nl1.NameListTile="NameBook1";for(inti=0;i<10;i++)nl1.AddName("Name"+i.ToString(

));

nl2.NameListTile="NameBook2";for(inti=0;i<5;i++)nl2.AddName("Book"+i.ToString(

));nl2[0]="ITBook_0";//通過索引設置實例的值

nl2[1]="ITBook_1";nl1.PrintNamelist(

);Console.WriteLine("NameList2Titleis{0}",nl2.NameListTile);for(intk=0;k<nl2.Count-1;k++)Console.WriteLine("\tNameList2[{0}]is{1}",k,nl2[k]);//通過索引讀取實例的值

}}}3.5屬性與索引staticvoidMain(str3.6委托與事件3.6.1委托委托是事件的基礎。它是一種變量類型,類似于C++中的函數指針,可以間接地實現與命名方法或匿名方法的關聯,提供在程序運行期間對不同方法(或函數)進行選擇的能力,即后聯編,但是,委托是類型安全和可靠的。與抽象方法類似,委托在聲明中指定了方法的返回類型和形式參數類型,但沒有指定具體的實現過程,其聲明格式如下:[修飾符]delegate類型委托名([參數列表]);其中修飾符和參數列表都是可選的。委托定義了方法的返回類型和參數列表,每一個使用委托的方法都必須與委托有著相同的簽名。定義了委托之后,便可以實例化委托,并在此基礎上實現與指定方法的關聯,進而可以通過委托實例調用相關聯的方法。委托方法的使用如代碼實例3.5所示。該實例實現了一個雇員類Employee,并在其中實現了按年齡比較大小和按薪資比較大小兩種比較方法,以此為基礎在測試類Test中利用委托實例做排序函數參數,進而實現了分別按照年齡和薪資的排序。3.6委托與事件3.6.1委托3.6委托與事件3.6.1委托usingSystem;namespaceEx_3_5{delegateboolCompareOp(objecto1,objecto2);//聲明委托

classEmployee{privateintm_age;privatedoublem_salary;privatestringm_name;publicEmployee(stringname,intage,doublesalary){m_name=name;m_age=age;m_salary=salary;}publicvoidPrint(

){Console.WriteLine("Nameis{0},ageis{1},salaryis{2}",m_name,m_age,m_salary);}

3.6委托與事件3.6.1委托3.6委托與事件3.6.1委托staticpublicboolAgeIsGreater(objecte1,objecte2){Employeeemp1=(Employee)e1;Employeeemp2=(Employee)e2;return(emp1.m_age>emp2.m_age)?true:false;}staticpublicboolSalaryIsGreater(objecte1,objecte2){Employeeemp1=(Employee)e1;Employeeemp2=(Employee)e2;return(emp1.m_salary>emp2.m_salary)?true:false;}}classTest{staticpublicvoidSort(object[]sortArray,CompareOpgtMethod)//使用委托做函數參數

{for(inti=0;i<sortArray.Length;i++){for(intj=i+1;j<sortArray.Length;j++){if(gtMethod(sortArray[j],sortArray[i])){objecttemp=sortArray[i];sortArray[i]=sortArray[j];sortArray[j]=temp;}}}}}3.6委托與事件3.6.1委托3.6委托與事件3.6.1委托staticvoidMain(string[]args){Employee[]employees={newEmployee("Wang",20,1000),newEmployee("Li",23,2019),newEmployee("Xu",34,2500),newEmployee("Liu",56,3000),newEmployee("Zhang",45,2300),newEmployee("Yuan",67,5000)};CompareOpCompareByAge=newCompareOp(Employee.AgeIsGreater);//定義委托實例

CompareOpCompareBySalary=newCompareOp(Employee.SalaryIsGreater);//定義委托實例

Console.WriteLine("Sortedbyage:");Sort(employees,CompareByAge);//委托實例作實參

for(inti=0;i<employees.Length;i++)employees[i].Print(

);Console.WriteLine("Sortedbysalary:");Sort(employees,CompareBySalary);//委托實例作實參

for(inti=0;i<employees.Length;i++)employees[i].Print(

);}}3.6委托與事件3.6.1委托staticv3.6委托與事件3.6.2事件

事件是使對象或類能夠提供通知的成員。如果將某個為用戶提供服務的類稱為服務類,使用服務的類稱為客戶類,則事件提供了一種在客戶類中擴展服務類的某個功能的機制,即在客戶類中可以定義事件響應函數。例如,在Windows程序中,窗口是一個對象,當用戶在其中單擊按鈕、按下按鍵、最大化或最小化窗口時都會激發(fā)響應事件,并且用戶可以為該響應事件添加執(zhí)行代碼。在C#中,事件機制的實現主要包括聲明事件、激活事件、聲明事件響應函數、訂閱事件等步驟,其中聲明事件、激活事件在提供事件通知的服務類中實現,而聲明事件響應函數和訂閱事件則在使用服務類的客戶類中實現。1.聲明事件事件的聲明通過委托來實現,先定義委托,再用委托聲明事件,并且通過委托將事件響應函數關聯到事件中。激發(fā)事件的時候通過調用委托實現對事件響應函數的調用。因此事件可以看成是一種特殊的委托,其聲明格式如下:修飾符event類型事件名;其中類型必須是委托類型。例如:publicdelegatevoidAlarmEventHandle(objectsender,stringmsg);//聲明委托publiceventAlarmEventHandleAlarm;//定義事件事件的聲明與字段的聲明類似,不同之處在于事件聲明包含一個event關鍵字,并且事件聲明的類型必須是委托類型。在包含事件聲明的類中,事件可以像委托類型的字段一樣使用。3.6委托與事件3.6.2事件3.6委托與事件3.6.2事件2.激活事件當事件激活條件滿足并且事件已經與某個事件響應函數關聯時便可以激活事件,即通過委托實例調用委托函數,如下:if((m_currentTime==m_alarmTime)&&(Alarm!=null))Alarm(this,"定時時間到!");//條件滿足時激活事件3.訂閱事件訂閱事件就是實現事件與事件響應函數的關聯,即委托實例與委托函數的關聯。在C#中通過“+=”操作符實現事件與事件響應函數的關聯,通過“-=”操作符將事件與已關聯的事件響應函數去除關聯,如下:t1.Alarm+=newAlarmEventHandle(OnAlarm);//事件響應函數與事件關聯t1.Alarm-=newAlarmEventHandle(OnAlarm);//去掉事件響應函數與事件的關聯如果事件沒有實現與事件響應函數的關聯則其值為null。3.6委托與事件3.6.2事件2.激活事件3.6委托與事件3.6.2事件4.聲明事件響應函數事件響應函數是客戶類在接收到服務類的事件通知后進行響應處理的函數,類似于回調函數。因此通過事件響應函數可以在客戶類中擴展服務類的某個功能。事件響應函數是委托實例的關聯函數,因此其簽名應與事件的簽名一致。下面的OnAlarm函數便是事件Alarm的事件響應函數。staticpublicvoidOnAlarm(objectsender,stringmsg)//聲明事件響應函數{Console.WriteLine("Alarmmessageis{0}",msg);}事件機制的使用如代碼實例3.6所示。該實例中定義了一個定時器類Timer,當定時事件與當前時間一致時將通知客戶程序,并通過與Alarm事件關聯的事件響應函數進行處理。而在測試類Test中定義了Timer類的對象,并將已定義好的事件響應函數與事件Alarm實現關聯,同時也測試了去掉關聯后的運行效果。3.6委托與事件3.6.2事件4.聲明事件響3.6委托與事件3.6.2事件usingSystem;namespaceEx_3_6{publicdelegatevoidAlarmEventHandle(objectsender,stringmsg);//聲明委托

classTimer{privateDateTimem_currentTime,m_alarmTime;//定義字段

publiceventAlarmEventHandleAlarm;//定義事件

publicTimer(DateTimect,DateTimeat){m_currentTime=ct;m_alarmTime=at;}publicDateTimeCurrentTime{get{returnm_currentTime;}set{m_currentTime=value;if((m_currentTime==m_alarmTime)&&(Alarm!=null))Alarm(this,"定時時間到!");//條件滿足時激活事件

}}

3.6委托與事件3.6.2事件usingS3.6委托與事件3.6.2事件publicDateTimeAlarmTime{get{returnm_alarmTime;}set{m_alarmTime=value;if((m_currentTime==m_alarmTime)&&(Alarm!=null))Alarm(this,"定時時間到!");//條件滿足時激活事件

}}}classTest{staticpublicvoidOnAlarm(objectsender,stringmsg)//聲明事件響應函數

{Console.WriteLine("Alarmmessageis{0}",msg);}staticvoidMain(string[]args){DateTimealarmtime=DateTime.Parse("6/2/201921:30:00");Timert1=newTimer(DateTime.Now,alarmtime);t1.Alarm+=newAlarmEventHandle(OnAlarm);//事件響應函數與事件關聯

t1.CurrentTime=alarmtime;//將激活事件響應函數

t1.Alarm-=newAlarmEventHandle(OnAlarm);//去掉事件響應函數與事件的關聯

t1.CurrentTime=alarmtime;//事件響應函數為空,不作處理

}}}3.6委托與事件3.6.2事件public3.7繼承與多態(tài)

3.7.1繼承現實世界中實體之間不是相互孤立的,它們往往具有共同的特征,也有著內在的差別。人們可以采用層次結構來抽象描述這些實體之間的相同之處和不同之處,如圖3.3所示的交通工具的分類。為了用程序語言對現實世界中的層次結構進行模型化,面向對象技術引入了繼承的概念,一個類可以從另一個類派生出來,派生類繼承了基類的相應特性,同時,派生類也可以作為其他類的基類,進而實現類間的層次繼承關系。因此,繼承是一種共性的抽象機制。圖3.3

交通工具的分類3.7繼承與多態(tài)3.7.1繼承圖3.3交3.7繼承與多態(tài)

3.7.1繼承1.繼承的定義

C++中,派生類可以繼承一個基類或多個基類的特性,而在C#中,派生類只能從一個類中繼承。派生類的聲明格式如下:[修飾符]class派生類名[:基類名]{

派生類成員

}

派生類能從它的直接基類中繼承的成員包括方法、字段、屬性、事件、索引,即除了構造函數和析構函數,派生類隱式地繼承了直接基類的所有成員。在C#中,關于繼承需要注意以下幾個重要規(guī)則。繼承是可傳遞的。如果C從B中派生,B又從A中派生,那么C不僅繼承了B中聲明的成員,而且繼承了A中的成員。派生類應當是對基類的擴展。派生類可以添加新的成員,但不能除去已經繼承的成員的聲明。構造函數和析構函數不能被繼承。除此之外的其他成員,不論對它們聲明了怎樣的訪問方式,都能被繼承。基類中成員的訪問方式只能決定派生類能否訪問它們。派生類如果聲明了與繼承而來的成員同名的新成員,就可以覆蓋已繼承的成員。但這并不意味著派生類刪除了這些成員,只是不能再訪問這些成員。類可以聲明虛方法、虛屬性,以及虛索引,它的派生類能夠重載這些成員,從而實現類的多態(tài)性。

3.7繼承與多態(tài)3.7.1繼承3.7繼承與多態(tài)

3.7.1繼承2.覆蓋在派生類的成員聲明中,可以聲明與繼承而來的成員同名的成員,并且使用相同的簽名。這時我們稱派生類的成員覆蓋了基類的成員。在C#中,要實現覆蓋的成員,一般在基類中將其聲明為virtual或override,而派生類中覆蓋成員聲明為override。即基類中的virtual成員在派生類中可以覆蓋,基類中的覆蓋成員在派生類中可以進一步聲明為覆蓋成員。其中用virtual修飾的成員稱為虛成員,而用override修飾的成員稱為覆蓋成員。如下所示:classShape{……virtualpublicvoidPrint(

)//虛方法

{Console.WriteLine("Shapeis{0}",name);}}classLineClass:Shape{……publicoverridevoidPrint(

)//覆蓋方法

{base.Print(

);Console.WriteLine("\tShapetypeisLine,Lengthis{0}",Length);}}

如果基類中的成員在派生類中被覆蓋了,則在派生類中直接用該成員名訪問的將是派生類中聲明的成員。為了在派生類中可以繼續(xù)訪問基類中的相應成員,在C#中引入了base關鍵字,通過該關鍵字可以訪問基類中的成員。因此,可以將base看成是一個指向派生類直接基類的引用,而this則是指向對象實例本身的引用。3.7繼承與多態(tài)3.7.1繼承3.7繼承與多態(tài)

3.7.1繼承3.object類為了提高程序員的編程效率,各種編程環(huán)境(工具)都提供了許多重用度高的類庫,以方便程序員直接使用。同樣,在.NET中也提供了相應的類庫。其中Object是該類庫中最基本的類,它屬于System命名空間,通常也寫成System.Object。在C#中,所有的類都直接或間接派生于Object類。在聲明類時,如果沒有明確指明基類,則編譯器會自動將Object類指定為其基類。因此,Object類是C#所有類的根,每個類都將從Object類繼承類成員。表3.3列出了Object類的常用方法。方法訪問修飾符作用stringToString(

)publicvirtual返回對象的字符串表示intGetHashTable(

)publicvirtual在實現字典(散列表)時使用boolEquals(objectobj)publicvirtual對當前對象與obj進行相等比較boolEquals(objectobjA,objectobjB)publicstatic在objA和objB之間進行相等比較boolReferenceEquals(objectobjA,objectobjB)publicstatic比較objA和objB是否引用的是同一個對象TypeGetType(

)public返回對象類型的詳細信息objectMemberwiseClone(

)protected進行對象的淺層復制voidFinalize(

)protectedvirtual該方法是析構函數的.NET版本3.7繼承與多態(tài)3.7.1繼承方法訪問3.7繼承與多態(tài)

3.7.2抽象類與密封類1.抽象類為了滿足分層次抽象的需要,在許多面向對象的程序設計語言中都引入了抽象類的概念。抽象類是基類的一種特殊形式,它除了擁有普通的類成員之外,還擁有抽象類成員。在C#中,抽象類成員是指那些只有聲明沒有實現的方法、屬性或索引,并且使用了abstract修飾符。因此,抽象類不能實例化,它一般出現在類層次結構中的中間層或根節(jié)點上,不能出現在葉節(jié)點中。在C#中,包含一個或多個抽象成員的類本身也必須聲明為abstract,但是抽象類可以包含非抽象的成員。從抽象類派生的類必須對基類中包含的所有抽象成員進行實現,否則它也是抽象類。抽象成員為隱式的虛成員,因此在抽象類的派生類中實現抽象成員的方法與覆蓋一個虛方法類似。如下代碼定義了一個抽象類Shape,其中包含抽象方法和虛方法。abstractclassShape//抽象類{privateintx,y;privatestringname;protectedColorTypeftColor;……abstractpublicvoidDraw(

);//抽象方法

virtualpublicvoidPrint(

)//虛方法

{Console.WriteLine("Shapeis{0}",name);}}3.7繼承與多態(tài)3.7.2抽象類與密封類3.7繼承與多態(tài)

3.7.2抽象類與密封類2.密封類密封類是指那些不能被繼承的類。在C#中,為了提高程序運行效率和穩(wěn)定性,對那些認定為不能再繼承的類可以定義為密封類,用修飾符sealed進行修飾。當一個類被聲明為密封類后,就不能再用來派生新的類。因此密封類中不可能存在抽象成員,一般也不存在虛成員。當某個類中的某個成員認定為不能被覆蓋時,也可以將其聲明為密封成員,即用修飾符sealed對該成員進行修飾。包含密封成員的類不一定要聲明為密封類。密封類可以從抽象類派生,也可以使用關鍵字override覆蓋基類中的虛成員。如下代碼定義了一個密封類SquareClass,它從基類RectClass派生而來。sealedclassSquareClass:RectClass//密封類

{publicSquareClass(stringname,intx,inty,intw,intl):base(name,x,y,x+w,y+l){}publicoverridevoidDraw(

){Console.WriteLine("Square{0}isdrawed",Name);}publicoverridevoidPrint(

){Console.WriteLine("Shapeis{0}",Name);Console.WriteLine("\tShapetypeisSquare,Lengthis{0},Areais{1}",Length,GetArea(

));}}

由抽象類和密封類的概念可知,在C#中,修飾符sealed和abstract不能同時出現在同一個類或同一個成員中。3.7繼承與多態(tài)3.7.2抽象類與密封類3.7繼承與多態(tài)

3.7.3接口在C#中,繼承的實現包括兩種方式:實現繼承和接口繼承。其中前面所介紹的類繼承方式屬于實現繼承,它實現的主要是抽象共享,或派生類對基類的修改和擴展等。接口繼承是一種對外約定的實現,在接口中定義相關的對外約定(包括方法、屬性、索引和事件),即類必須實現的對外行為特征,實現接口的類則實現了這些約定。這樣客戶程序只要了解類所實現的接口便可以知道其對外提供了哪些服務。在C#中,定義接口的語法規(guī)則如下:

[訪問修飾符]interface接口名[:父接口列表] {

接口成員

}

其中接口成員可以是方法、屬性、索引和事件的聲明,但僅僅是聲明,不需要給出實現體,這與抽象類中的抽象成員類似。父接口列表用于指定接口繼承的父接口,這與類有很大區(qū)別,接口允許多繼承,因此,該列表可以包含無數個接口。如下代碼定義了兩個接口IRegion和ILine,其中一個接口定義的是方法,另一個定義的是屬性。publicinterfaceIRegion{doubleGetArea(

);}publicinterfaceILine{doubleLength{get;}}

接口最終還是要通過類來實現,即要求類來實現接口中的接口成員,這與派生類要實現基類中的抽象成員一樣。另外,由于接口中聲明的僅僅是功能約定,即抽象的功能成員,沒有數據成員,因此不會由于多重繼承帶來二義性問題。在C#中,一個類最多可以有一個基類,但是可以具有無限個接口。3.7繼承與多態(tài)3.7.3接口接3.7繼承與多態(tài)

3.7.4多態(tài)性多態(tài)性是面向對象技術中的一個重要概念。是指通過基類引用綁定不同對象實例時,同樣的方法可以具有不同的運行行為,即對象運行時刻的類型決定它的行為,而不是它的引用方法編譯時的類型決定它的行為。在C#中,多態(tài)性的實現依賴于基類中的虛成員聲明以及派生類中對虛成員的覆蓋。如下代碼表現了多態(tài)性的實現。Shapel1=newLineClass("Line1",10,10,20,40);Shaper1=newRectClass("Rect1",20,20,40,50);Shapes1=newSquareClass("Square1",30,30,20,30);l1.Draw(

);l1.Print(

);//依據Draw和Print在LineClass中的實現來執(zhí)行r1.Draw(

);r1.Print(

);//依據Draw和Print在RectClass中的實現來執(zhí)行s1.Draw(

);s1.Print(

);//依據Draw和Print在SquareClass中的實現來執(zhí)行因此,通過對象引用調用的方法的執(zhí)行行為,取決于該對象引用動態(tài)綁定的對象類型。多態(tài)性在程序運行的動態(tài)過程中體現,進而增加了程序的靈活性和通用型。繼承與多態(tài)的實現方法如代碼實例3.7所示,該實例中定義了抽象類Shape、接口IRegion和ILine、具體類LineClass、RectClass和SquareClass。3.7繼承與多態(tài)3.7.4多態(tài)性3.7繼承與多態(tài)

3.7.4多態(tài)性usingSystem;namespaceEx_3_7{enumColorType{Red,Green,Blue,Black,White,Yellow};abstractclassShape{privateintx,y;privatestringname;protectedColorTypeftColor;publicShape(

){name="Nonename";x=0;y=0;}publicShape(stringname,intx,inty){=name;this.x=x;this.y=y;}publicColorTypeFtColor{get{returnftColor;}set{ftColor=value;}}

3.7繼承與多態(tài)3.7.4多態(tài)性3.7繼承與多態(tài)

3.7.4多態(tài)性

publicintX{get{returnx;}set{x=value;}}publicintY{get{returny;}set{y=value;}}publicstringName{get{returnname;}}abstractpublicvoidDraw(

);virtualpublicvoidPrint(

){Console.WriteLine("Shapeis{0}",name);}}

3.7繼承與多態(tài)3.7.4多態(tài)性3.7繼承與多態(tài)

3.7.4多態(tài)性publicinterfaceIRegion{doubleGetArea(

);}publicinterfaceILine{doubleLength{get;}}classLineClass:Shape,ILine{privat

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論