3.1 面向對象簡介
面向對象不僅是一項具體的軟件開發技術,也是一種符合人類思維習慣的編程思想。現實生活中存在各種形態不同的事物,這些事物之間存在着各種各樣的聯繫。面向對象編程(object-oriented programming,OOP)就是利用對象模型技術分析目標問題,抽象出相關對象的共性,並對共性進行分類及分析各類之間的關係,同時使用類描述同一類問題。
面向對象中類的定義充分體現了抽象數據類型的思想,基於類的體系結構可以把程序的修改局部化,特別是一旦系統功能需求要修改時,只要修改類中間的某些操作,而類所代表的對象基本不變,保持整個系統仍然穩定。
3.2 類與對象
面向對象的編程思想力圖使程序對事物的描述與該事物在現實中的形態保持一致,爲了做到這一點,在面向對象的思想中提出了兩個概念,即類和對象。
類是對某一類事物的抽象描述,對象是該類事物的某一個實體,對象會被分配物理內存。
3.2.1 類的聲明
創建對象,首先需要聲明一個類,用於描述一組對象的特徵和行爲。類中可以定義字段、屬性、方法等成員。定義在類中的變量稱爲字段,字段用於在類中存儲數據,屬性用於描述對象的特徵,而方法用於描述對象的行爲。
注意:若類的聲明中沒有指定字段的初始值,使用對象時也沒有給字段賦值,則編譯時會自動賦予其類型的默認值併發出警告。
聲明類的語法格式:
[訪問修飾符] class 類名稱 [: 基類或接口]
{
類成員定義
}
代碼實例
3.2.2 對象的創建與使用
1) 對象的創建
語法格式:
類名 對象名稱 = new 類名();
Person p = new Person();
new Person()創建一個對象並對其初始化
p是一個引用,指向new Person()創建出來的對象
參考:https://blog.csdn.net/yl2isoft/article/details/23521083
2) 對象的使用
語法格式:
對象引用.對象成員
p.Speak();
3.3 類的數據成員
類的成員包括:類的常量、字段、屬性、索引器、方法、事件、構造方法等,其中常量、字段、屬性都是與類的數據有關的成員。
1)常量
在類中的常量是一種符號常量,符號常量是由用戶根據需要自行創建的常量,可能需要反覆使用。
2)字段
字段表示類的成員變量,字段的聲明方式即變量的聲明方式,字段的值代表某個對象數據狀態,字段使類具備封裝數據的能力,一般情況下,應將字段聲明爲private,然後通過屬性或方法訪問其內容。
3)屬性
在C#中,爲保證類中內部的數據的安全,可以使用屬性封裝字段,首先需要將字段訪問級別設置爲private,再通過屬性的get和set訪問器對字段進行讀寫操作,具體語法格式如下:
[訪問修飾符] 數據類型 屬性名
{
get{獲得屬性的代碼;}
set{設置屬性的代碼;}
}
如果設置讀寫屬性,需要同時使用get和set訪問器;
如果設置只讀屬性,只需要使用get訪問器,一般用於在構造方法中給屬性賦值,在程序運行過程中不能修改該屬性的值;
如果設置只寫屬性,需要使用set訪問器,在程序運行過程中只能寫入值而不能讀取值;
如果設置自動屬性,則不需要書寫任何屬性的代碼,也就是在get和set訪問器後面不加大括號,直接加”;”即可。
注意:在自動屬性中,無須定義一個相應的私有字段,也不必寫任何return和value語句。自動屬性雖然簡潔,但不能通過屬性 完成任何更多的復雜邏輯。
代碼實例
3.4 方法
在類中自定義的“函數”稱爲“方法”。方法是表示實現類功能而執行的計算或操作。
3.4.1 方法的定義與調用
每個方法都有一個名稱和一個主體。方法名是一個有意義的標識符,用來描述方法的用途;方法主體包含了調用方法時實際執行的語句。定義方法的語法格式如下:
[訪問修飾符] 返回值類型 方法名(參數列表)
{
方法體
[return 返回值;]
}
上述語法需要注意以下幾點:
(1)方法的返回類型是指調用方法後 返回值的類型;
(2)參數可有可無,參數列表中的形參 和 實際調用時傳遞的實參,一一對應,個數和數據類型必須一致;
(3)方法調用有3種:
1) 在同一類中,方法可以直接調用;
2) 在其它類中,需要通過類的實例進行調用;
3) 靜態方法需要通過類名進行調用。
代碼實例
3.4.2 方法的重載
方法重載是一種操作性多態。當需要在 多個不同的實現 中 對不同的數據 進行 相同的邏輯操作時,就可以使用重載。
方法重載指在同一個類中創建多個同名的方法,但這些方法的參數互不相同,可以是參數類型不同,也可以是參數個數不同。決定方法 是否構成重載的3個條件如下:
(1)在同一個類中;
(2)方法名相同;
(3)參數列表不同。
代碼實例
3.4.3 方法的高級參數
爲了讓方法的調用更加靈活,C#中引入了高級參數的概念。通過高級參數可以實現兩個功能,一是調用方法時允許傳入任意個數的參數,而不受形參個數的約束;二是允許在方法中修改方法以外變量的值。高級參數有以下3種:
(1)params參數:用於實現方法接收任意個數的參數;
(2)ref參數:用於傳遞參數的引用,而不是參數的值;
(3)out參數:用於將值從方法體內傳到方法體外。
1. params參數
params參數在定義時不需要確定參數的個數,可以使用params關鍵字加上數組的方式作爲方法的參數,在調用方法時傳入任意個數類型相同的參數即可。
注意:
(1) 一個方法中最多只能出現一個params;
(2) params關鍵字只能放到所有參數的最後面,即params修飾的參數後面不能再有其他參數;
(3) 當參數爲params修飾時,要防止外界傳入非法參數,如null。
2. ref參數
在使用引用傳遞時,需要在參數前面加上ref關鍵字,並在調用方法時也使用ref關鍵字,就可以實現當方法執行後,外面的變量值保持方法內修改後的結果
3. out參數
out參數也用於實現引用傳遞,使用out參數可以將值從方法體內傳到方法體外。
4. ref和out區別
參考:https://www.cnblogs.com/sunliyuan/p/5999045.html
ref和out的區別在C# 中,既可以通過值也可以通過引用傳遞參數。通過引用傳遞參數允許函數成員更改參數的值,並保持該更改。若要通過引用傳遞參數, 可使用ref或out關鍵字。ref和out這兩個關鍵字都能夠提供相似的功效,其作用也很像C中的指針變量。
它們的區別是:
1、使用ref型參數時,傳入的參數必須先被初始化。對out而言,必須在方法中對其完成初始化。
2、使用ref和out時,在方法的參數和執行方法時,都要加Ref或Out關鍵字。以滿足匹配。
3、out適合用在需要retrun多個返回值的地方,而ref則用在需要被調用的方法修改調用者的引用的時候。
out:
方法參數上的 out 方法參數關鍵字使方法引用傳遞到方法的同一個變量。當控制傳遞迴調用方法時,在方法中對參數所做的任何更改都將反映在該變量中。
當希望方法返回多個值時,聲明 out 方法非常有用。使用 out 參數的方法仍然可以返回一個值。一個方法可以有一個以上的 out 參數。
若要使用 out 參數,必須將參數作爲 out 參數顯式傳遞到方法。out 參數的值不會傳遞到 out 參數:。
不必初始化作爲 out 參數傳遞的變量。然而,必須在方法返回之前爲 out 參數賦值。
屬性不是變量,不能作爲 out 參數傳遞。
ref是 有進有出,而out是 只出不進。
5. 形參 實參 引用間的關係
發生函數調用的時候,有 按值傳遞 和 按引用傳遞 這兩種方式。對於按值傳遞是將實參的值拷貝給形參,雖然此時形參和實參的值相同,但是形參和實參分別佔據不同的內存空間,所以一旦函數調結束,形參佔據的內存空間就會釋放,故方法中對形參的任何改變都不會影響實參的值。而ref和out都是引用類型,所以屬於按引用傳遞,對於按引用傳遞的方式,形參和實參共享同一塊內存空間,故在方法中對形參的改變,其實就是對實參值的改變,即使函數調用結束,方法中對形參的改變即是對實參的改變,這種改變在函數調用結束後仍舊保持。
由於ref和out修飾的參數同屬按引用傳遞,所以對於函數重載,ref和out類型是同一種類型;
不使用ref和out修飾的參數,不一定就是按值傳遞的。例如,數組、集合等都是引用類型,故不必使用ref修飾,也是按引用傳遞的。
6. 代碼實例
3.5 構造方法
構造函數時類的一個特殊成員,會在類實例化對象時自動調用,爲對象開闢內存空間,並對類中的成員進行初始化。
C# 中每個類至少有一個構造方法,當聲明一個類時,若沒有定義構造方法,系統會自動添加一個默認的沒有參數的構造方法,在其方法體內沒有任何代碼,即什麼也不做。反之,若聲明類時定義了構造方法,系統將不會自動添加默認的構造方法。
在一個類中定義構造方法,必須滿足以下3個條件:
(1)方法名與類名相同;
(2)在方法名的前面沒有返回值類型的聲明;
(3)在方法中不能使用return 語句返回一個值。
代碼實例
3.6 訪問修飾符與static關鍵字
3.6.1 訪問修飾符
C#中,4種訪問修飾符,可以組合成5個可訪問級別,訪問級別從高到低描述如下:
(1)public:公有訪問,最高級別訪問,訪問不受任何限制;
(2)protected:保護訪問,只限於本類和子類訪問,實例不能訪問;
(3)internal:內部訪問,只限於本項目中的類或子類訪問,其它不能訪問;
(4)protected internal:內部保護訪問,只限於本項目中的類或子類訪問,其它不能訪問;
(5)private:私有訪問,最低訪問級別,只限於在聲明它們的類和結構中才可以訪問,子類和實例都不能訪問。
在使用訪問修飾符定義命名空間、結構和類及其成員時,要注意以下幾點:
(1)一個成員或類型只能有一個訪問修飾符,使用protected internal組合時除外;
(2)命名空間上不允許使用訪問修飾符,命名空間沒有訪問限制;
(3)如果未指定訪問修飾符,則使用默認的可訪問性,類的成員默認爲private;
(4)訪問修飾符只是控制外部對內部成員的訪問,類的內部對自己的訪問不受其限制,即在類的內部可以訪問所有的類成員。
3.6.2 static關鍵字
static關鍵字用於修飾類、字段、屬性、方法以及構造方法等。被static修飾的成員稱爲靜態成員,包括靜態字段、靜態屬性、靜態方法等;被static修飾的類稱爲靜態類。
靜態成員與非靜態成員的不同在於:靜態成員屬於類,而不屬於類的實例,因此,需要通過類而不通過類的實例訪問;而非靜態成員總是與特定的實例(對象)相聯系。
在實際應用中,當類的成員引用或操作的信息是屬於類的實例時,就應該設置爲靜態成員。???
1靜態字段
靜態成員屬於類,而不屬於類的實例,因此,需要通過類而不通過類的實例訪問;而非靜態成員總是與特定的實例(對象)相聯繫。
語法格式:類名.靜態字段名
2靜態屬性
靜態屬性可以讀寫靜態字段的值,並保證靜態字段值的合法性,訪問靜態屬性的語法格式如下:
類名.靜態屬性
3靜態方法
當希望不創建對象就可以訪問某個方法時,可以將該方法定義成靜態方法,訪問靜態方法的語法格式如下:
類名.靜態方法名
4靜態類
當類的成員全部是靜態成員時,就可以把這個類聲明爲靜態類。靜態類具有的有點:編譯器能夠自動執行檢查,以確保不添加實例成員;靜態類能夠使程序的實現更簡單、迅速,因爲不必創建對象就能調用其方法。
靜態類特點:
(1)靜態類僅包含靜態成員
(2)靜態類不能被實例化
(3)靜態類是密封的
(4)靜態類不能包含實例構造方法
5綜合代碼實例
3.7 面向對象的基本特徵
面向對象的3個基本特徵是:封裝、繼承、多態
封裝是指 將客觀事物封裝成抽象的類,並且類可以把自己的數據和方法只讓可信的類或對象操作,對不可信的類進行信息隱藏。通常,一個類就是一個封裝了數據以及操作這些數據的代碼邏輯實體。
繼承是指 可以讓某個類型的對象獲得另一個類型對象的屬性和方法。通過繼承創建的新類稱爲“子類”或“派生類”,被繼承的類稱爲“基類”“父類”或“超類”。繼承的過程,就是從一般到特殊的過程。
多態是指 一個類的實例的相同方法在不同情形有不同的表現形式。多態機制使具有不同內部結構的對象可以共享相同的外部接口。這意味着,雖然針對不同對象的具體操作不同,但通過一個公共的類,這些操作可以採用相同的方式予以調用。
3.7.1 封裝
C#中可以使用類達到數據封裝的效果,這樣就可以使數據與方法封裝成單一元素,以便通過方法存取數據。
3.7.2 繼承
C#中提供了類的繼承機制,但只支持單繼承,而不支持多重繼承。利用繼承機制,可以通過增加、修改或替換類中的方法對這個類進行擴充,以適應不同的應用需求。繼承使子類可以從父類自動地獲得父類所具備的特性,故可以極大地節省代碼,提高代碼的可重用性。
繼承的語法格式如下:
[訪問修飾符] class 類名:基類名
{
類成員;
}
注意:
在C#中,類的繼承遵循以下原則:
(1)派生類只能從一個類中繼承,即單繼承。
(2)派生類自然繼承基類的成員,但不能繼承基類的構造方法。
(3)類的繼承可以傳遞。若類C繼承於類B,類B又繼承於類A,那麼類C具有類A和類B的成員。
3.7.3 多態
在C#中,類的多態性是通過在子類(派生類)中重寫基類的虛方法或方法成員實現的。若一個方法在定義中含有virtual修飾符,則該方法稱爲虛方法。虛方法的實現可以由派生類取代,取代所有繼承的虛方法的實現過程稱爲重寫(override)。
3.8 抽象類與嵌套類
抽象類和嵌套類的概念是面向對象設計中常用的概念。抽象類往往用來表示對問題領域進行分析、設計中得出的抽象概念,是對一系列看上去不同,但是本質上相同的具體概念的抽象。嵌套類的目的在於隱藏類名,減少全局的標識符,從而限制用戶使用該類建立對象,這樣可以提高類的抽象能力,並且強調了兩個類(外部類和嵌套類)之間的主從關係。
3.8.1 抽象類
基類並不與具體的事物聯繫,而只是表達一種抽象的概念時,可以將此基類定義爲抽象類,用於爲它的派生類提供一個公共的界面。
抽象類是類,可以包含具體的功能實現代碼。抽象類以abstract修飾;不能被實例化,只能供其它類繼承;含有抽象方法的類一定要聲明爲抽象類,但反過來抽象類可以不包含抽象方法。
注意:
(1)抽象類只能作爲其它類的基類,不能直接被實例化,而且對抽象類不能使用new操作符;
(2)包含抽象類方法的類必須聲明爲抽象類,但抽象類可以不包含抽象方法;
(3)如果一個非抽象類從抽象類中派生,則其必須通過重寫實現所有繼承而來的抽象成員。
抽象類與接口的聯繫與區別:
參考:
https://www.cnblogs.com/jian1125/p/10530125.html https://www.cnblogs.com/sunzhenyong/p/3814910.html
https://blog.csdn.net/xiangrublog/article/details/20392781
3.8.2 嵌套類
在C#中,可以將類定義在另一個類的內部,被包含的類稱爲嵌套類,而包含嵌套類的類稱爲外部類。
3.9 委託與Lambda表達式
3.9.1 委託
委託是一種動態調用方法的類型。在C#程序中,可以聲明委託類型、創建委託的實例、把方法封裝於委託對象中,這樣就可以通過該對象調用方法了。
委託對象本質上代表了方法的引用。在 .NET Framework中,委託有以下特點:
- 委託類似於C++的函數指針,但與函數指針不同的是,委託是完全面向對象的,是安全的數據類型;
- 委託允許將方法作爲參數進行傳遞;
- 委託可用於定義回調方法;
- 委託可以把多個方法鏈接在一起,這樣在事件觸發時,可以同時啓動多個事件處理程序。
1 聲明委託
委託使用關鍵字delegate來聲明,語法格式:
[訪問修飾符]delegate 返回值類型 委託名 ([形參列表])
其中,訪問修飾符可選,返回值類型和委託名是必要的,形參列表用來指定委託所表示方法的參數,也是可選的。
例如:public delegate int Calculate(int x, int y);
2 委託實例化
委託對象必須用new關鍵字創建,且與一個特定的方法有關。當創建委託時,傳遞到new語句的參數就像方法調用一樣書寫,但是不帶有參數。語法格式:
委託類型 委託變量名 = new 委託類型構造方法 (委託要引用的方法名)
3 使用委託
在實例化委託之後,就可以通過委託對象調用它所引用的方法。在使用委託對象調用所引用的方法時,必須保證參數的類型、個數、順序和方法聲明匹配。
4 代碼示例
3.9.2 Lambda表達式
Lambda表達式本質上就是匿名方法,只是將匿名方法的書寫方式進一步簡化。由於方法需要依附於委託,所以Lambda表達式的書寫也要遵循委託的限制。語法格式:
(參數列表)=>{語句序列};
注意:
- 參數列表中可以有0個,1個或更多參數,參數個數由相應的委託確定。
(2)當參數列表中只有一個參數時,參數列表外側的一對括號可以省略。
(3)當編譯器能夠推斷參數的類型時,在參數列表中可以不必確定參數類型,只需要參數的名稱即可。
(4)如果在委託聲明時對參數使用了ref或out修飾,則Lambda表達式中也必須帶上ref或out,並且此時不能省略參數類型。
(5)當右側的語句序列只有一條語句時,大括號可以省略,否則不能省略。
(6) 當右側的語句序列有返回值,必須使用return語句,但是若右側語句序列中只有一個語句,則return語句可以省略。
(7)如果委託有返回值類型,則Lambda表達式也必須返回相同類型的值。
代碼示例
3.10 程序集
在程序開發時可能會用到其它程序中的類,此時就需要使用程序集。程序集就是包含一個或多個類型的定義文件和資源文件的集合,該程序集中的文件可以被其它程序使用。
1生成程序集
1)創建類庫
2)編寫類庫中的類
3)生成程序集
2引用程序集
新建項目ConsoleApplication,右擊項目,選擇“添加”->“引用”命令,打開“引用管理器”對話框,將相應.dll文件添加進去即可。
3使用程序集中的類
可參考:
https://blog.csdn.net/u010026134/article/details/51598499