.NET Core CSharp 初級篇 1 3 本節內容為面向對象初級教程 類 簡介 面向對象是整個C 中最核心最有特色的一個模塊了,它很好的詮釋了程式與現實世界的聯繫。 面向對象的三大特征:繼承、多態、封裝;繼承的含義可以理解為集合中的包含關係,例如人類屬於動物類的一個分支,這就是一種繼承。多態 ...
.NET Core CSharp初級篇 1-3
本節內容為面向對象初級教程
類
簡介
面向對象是整個C#中最核心最有特色的一個模塊了,它很好的詮釋了程式與現實世界的聯繫。
面向對象的三大特征:繼承、多態、封裝;繼承的含義可以理解為集合中的包含關係,例如人類屬於動物類的一個分支,這就是一種繼承。多態的理解就可以是人的呼吸用肺,鯉魚使用鰓,這就是一種同種操作對應不同的實現。封裝可以理解為一堆零件可以組成一個手機,這個過程就叫做封裝。而將電腦顯卡等拆下來組裝成另一臺電腦,則屬於類的拆箱裝箱。
封裝一個類的好處在哪裡呢?我舉一個例子:
首先,我們考察一個常見的生活實例來進行說明,例如每當發工資的日子小王都來到 ATM 機
前,用工資卡取走一筆錢為女朋友買禮物,從這個很帥的動作,可以得出以下的結論:
- 小王和 ATM 機之間,以銀行卡進行交互。要取錢,請交卡。
- 小王並不知道 ATM 機將錢放在什麼地方,取款機如何計算錢款,又如何通過銀行卡返回小王
所要數目的錢。對小王來說,ATM 就是一個黑匣子,只能等著取錢;而對銀行來說,ATM 機就
像銀行自己的一份子,是安全、可靠、健壯的員工。 - 小王要想取到自己的錢,必須遵守 ATM 機的對外約定。他的任何違反約定的行為都被視為不
軌,例如欲以磚頭砸開取錢,用公交卡冒名取錢,盜卡取錢都將面臨法律風險,所以小王只能
安分守己地過著月光族的日子。
那麼小王和 ATM 機的故事,能給我們什麼樣的啟示?對應上面的 3 條結論,我們的分析如下: - 小王以工資卡和 ATM 機交互信息,ATM 機的入卡口就是 ATM 機提供的對外介面,磚頭是塞不
進去的,公交卡放進去也沒有用。 - ATM 機在內部完成身份驗證、餘額查詢、計算取款等各項服務,具體的操作對用戶小王是不
可見的,對銀行來說這種封閉的操作帶來了安全性和可靠性保障。 - 小王和 ATM 機之間遵守了銀行規定、國家法律這樣的協約。這些協約和法律,就掛在 ATM 機旁邊的牆上。
具體來說,封裝隱藏了類內部的具體實現細節,對外則
提供統一訪問介面,來操作內部數據成員。這樣實現的好處是實現了 UI 分離,程式員不需要知道
類內部的具體實現,只需按照介面協議進行控制即可。同時對類內部來說,封裝保證了類內部成
員的安全性和可靠性。在上例中,ATM 機可以看做封裝了各種取款操作的類,取款、驗證的操作
對類 ATM 來說,都在內部完成。而 ATM 類還提供了與小王交互的統一介面,並以文檔形式——
法律法規,規定了介面的規範與協定來保證服務的正常運行
類屬於在堆分佈的變數,意味著它的大小是不固定的。可以動態的進行調節。
創建與實例化類
類的創建非常的簡單,實例化也非常的簡單,創建類就是把一個具體的事物抽象化,實例化就是將抽象化的類給轉換成具象化的對象。例如我們定義一個People類,內含若幹個變數;
//定義類使用class關鍵字
class People
{
public string Name;
public int Age;
}
//實例化類
People p = new People();
或許你還看不太懂這些,別急,請繼續往下看。
修飾符
訪問控制修飾符
- public:對訪問沒有任何限制,屬於最高級別的訪問許可權
- private:私有許可權,最低級別的訪問,只能在聲明的代碼段(類)中使用。
- protected:保護許可權,只有繼承了該類才可以使用。
- internal:僅包含當前程式集使用
- protect internal:同一個程式集的類和其派生的類可以使用
這樣說或許過於抽象,我們這樣來解釋吧,一個程式就類似一個公司,public就好比是董事長、CEO一類的許可權,擁有著最高級別的訪問;protected你可以理解為部門經理,它的下屬就是繼承該部門,下屬可以訪問父類(部門)的資源,但不可以訪問其他部門的protected資源,體現為一種縱向的許可權控制。Internal類似與考勤部門,無論該部門是否屬於考勤部門領導,考勤部門都可以管轄其他部門,體現為一種橫向的許可權控制。Protected internal則是具有兩種屬性。
可選修飾符
- static(可用於類內成員):靜態的,表示只被創建一次,屬於所有對象公用的變數
- sealed:密封類,禁止類被繼承
- abstract:抽象類,要求類被繼承,並且不能實例化
- virtual(不能用於類):表示可以被重寫
- readonly(用於欄位):表示該欄位只讀
- const(用於欄位):表示常量
- extern(用於函數):表示該函數由外部實現
- async(用於函數):表示該函數為非同步函數
函數
函數也被稱為方法,是包含一系列語句的代碼塊。封裝了類的行為,提供了類的對外表現。用於將封裝的內部細節以公有方法提供對外介面,從而實現與外部的交互與響應。例如,從上面屬性的分析我們可知,實際上對屬
性的讀寫就是通過方法來實現的。因此,對外交互的方法,通常實現為 public。程式通過調用該方法並指定任何所需的方法參數使語句得以執行。 在 C# 中,每個執行的指令均在方法的上下文中執行。
函數的構成由訪問控制關鍵字+修飾符+返回值+函數名稱+函數參數+函數體,如果一個類內函數或者其他成員使用了static關鍵字,則可以不實例化類對其進行調用,因為使用了static標明的成員,屬於全體該類對象共有。例如下麵這個例子:
class Man
{
static void GettingOld()
{
//life - 1s
}
public void Eat()
{
}
}
//靜態方法可以直接調用
Man.GettingOld();
Man man = new Man();
man.Eat();
函數的使用如下,其中x,y稱為形參,x1,y1稱為實參,通常對形參的操作並不會影響到實參
public static int Add(int x,int y)
{
x++;y++;
return x+y;
}
int x1 =5;
int y1 =6;
Add(x1,y1);
//帶有預設參數
public static int Add(int x,int y=4)
{
}
//不定參數
public void Add(params object[] a)
{
}
當然不是所有的方法都被實現為 public,否則類內部的實現豈不是全部暴露在外。必須對對外
的行為與內部操作行為加以區分。因此,通常將在內部的操作全部以 private 方式來實現,而將需要與外部交互的方法實現為 public,這樣既保證了對內部數據的隱藏與保護,又實現了類的對外交互。例如在 ATM 類中,對錢的計算、用戶驗證這些方法涉及銀行的關鍵數據與安全數據的保護問題,必須以 private 方法來實現,以隱藏對用戶不透明的操作,而只提供返回錢款這一 public 方法介面即可。在封裝原則中,有效地保護內部數據和有效地暴露外部行為一樣關鍵。
函數的重載與重寫
重載函數表示使用同一個函數名,通過參數的不同,從而實現使用同一個名稱可以選擇調用多種函數。例如實現兩個數字的相加,傳入的有可能是整型參數也有可能是浮點型參數,因此,我們選擇使用重載函數去實現。以下是一個重載的例子;
public static int Add(int x,int y)
{
return x+y;
}
public static double Add(double x,double y)
{
return x+y;
}
Add(1,2);//調用第一個Add
Add(1.1,2.2);//調用第二個函數
通過調用函數時傳入的參數不同,就可以很簡單的用不同方法實現。
函數重寫則多出現在面向對象的多態性中,這裡我不會很詳細的講解,在後面會有一個詳細的講解。重寫就可以理解為,人呼吸用肺,大部分魚類呼吸用鰓,呼吸這個函數就是在兩個類中被重寫過(即實現方法在不同的類中)。具體的實現我會在後一步進行講解
需要註意的是,重載需要在參數上有本質的區別,例如個數、類型不同,重寫則需要方法可以被重寫,使用override關鍵字表明重寫的函數
類中重要的兩個函數
構造函數:構造函數是一種特殊的函數,它的簽名和類名一致,並且沒有返回值。它可以接受任意個參數。當類被實例化的時候,對應的構造函數會被調用。可以說,對象是通過調用類的構造函數進行創建。如果不指定構造函數,C#會自動調用預設的無參構造函數。如果重載了構造函數,並且傳入了指定參數,則會調用對應的構造函數。
析構函數:類似與構造函數,但是調用是在GC(垃圾回收器)回收類對象的時候自動調用,通常無需去重寫。例如:
class A
{
//預設無參構造函數
public A()
{
}
public A(int a)
{
}
// 析構函數
~A()
{
}
}
A a = new A(1);//調用第二個構造函數
欄位和屬性
(此處補充IL代碼)
欄位:類中具體實現存儲數據的變數,你可以理解為各個零件。通常而言,欄位不會對外進行開發訪問許可權。例如:幼兒園讀書的小朋友類,裡面有一個Age(年齡)欄位。假設一個人實例化,我們給年齡賦值上1000。這符合常理嗎?顯然是不符合的。那麼我們就要使用屬性進行控制輸入的變數。
屬性:屬性不存儲數據,通常定義為 public,表示類的對外成員。屬性具有可讀、可寫屬性,通過 get 和 set 訪問器來實現其讀寫控制。但是如果你使用預設的屬性實現方法,例如public string a {get;set;},C#會自動的為你隱式生成一個私有的欄位a。屬性本質上是作為外部訪問欄位的一個媒介、橋梁,也稱之為介面。通常來說,我們會將欄位定義為私有的,將屬性定義為公有的,通過屬性去返回和設置其中的值。在這裡,我們涉及到了兩個從未見過的關鍵字——get,set。
get訪問器:get訪問器本質上是一個返回值為屬性類型的函數,你可以使用dnSpy進行反編譯查看。你一般需要在get中返回你需要訪問的變數。
set訪問器:使用value關鍵字接受外界傳來的參數並且賦值給你的欄位,本質上也只是一個函數,當你對屬性賦值的時候,就會調用他的set控制塊內的代碼
class A
{
private int a;
public int A
{
get{return a;}
set
{
if(value>5)
{
a=value;
}
}
}
//自動生成一個b欄位
public int B{get;set;}
}
練習題
請試著創建一個圓類(Circular),要求封裝圓周率和半徑(或直徑),並且定義一個含有一個參數的構造函數,傳入的是半徑(直徑)。並寫入計算周長和麵積的函數。
定義一個用戶類,要求用戶名和密碼不可以被訪問,只允許設置,並且密碼小於6位需要輸出相應提示並且不進行賦值要求重新賦值。
前往Github獲取更多本節資料(PPT,實例代碼)
如果我的教程幫到了您,希望您動動小手,在GitHub給我一個star
Reference
《你必須知到的.NET》