.NET Core CSharp初級篇 1-3物件導向

WarrenRyan發表於2019-07-18

.NET Core CSharp初級篇 1-3

全文目錄

(部落格園).NET Core Guide

(Github).NET Core Guide

本節內容為物件導向初級教程

簡介

物件導向是整個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;}
}

選看 函式引數修飾符

對C#瞭解的人都知道,實參到形參的傳遞時存在一個資料備份的過程,因此我們對形參的操作本質上是對備份的變數進行操作,並不會影響到實參的值。但是在C#中,可以對形參進行修飾,使傳入的變數按記憶體地址進行傳入,這樣就可以實現改變實參的值了。

ref 關鍵字

ref關鍵字的要求有以下幾點:

  • 被呼叫函式的引數和呼叫時都必須使用ref標記引數
  • 傳遞到 ref 引數的引數必須初始化,否則程式會報錯

例如:

        static void Main(string[] args)
        {
            int a = 10;
            int b = 20;
            Test(ref a,ref b);
            Console.WriteLine("a:{0},b:{1}", a, b);
        }
        static void Test(ref int a, ref int b) 
        {
            a = a+b;  
            b = 6;
        }

out 關鍵字

out關鍵字的要求有以下幾點:

  • 方法定義和呼叫方法都必須顯式使用 out關鍵字

  • out關鍵字無法將引數值傳遞到out引數所在的方法中,只能傳遞引數的引用,所以out引數的引數值初始化必須在其方法內進行,否則程式會報錯

        static void Main(string[] args)
        {
            int a=100;
            int b;
            Test(out a, out b);
            Console.WriteLine("a:{0},b:{1}", a, b);
        }
        static void Test(out int a, out int b)
        {
            a = 1+2;
            b = 1;
        }

in關鍵字

in關鍵字的要求有:

  • 它讓形參成為實參的別名,這必須是變數。 換而言之,對形參執行的任何操作都是對實參執行的。
  • in 引數無法透過呼叫的方法進行修改。 out 引數必須由呼叫的方法進行修改,這些修改在呼叫上下文中是可觀察的,而 ref 引數是可以修改的
int readonlyArgument = 44;
InArgExample(readonlyArgument);
Console.WriteLine(readonlyArgument);     // value is still 44

void InArgExample(in int number)
{
    // Uncomment the following line to see error CS8331
    //number = 19;
}

練習題

  • 請試著建立一個圓類(Circular),要求封裝圓周率和半徑(或直徑),並且定義一個含有一個引數的建構函式,傳入的是半徑(直徑)。並寫入計算周長和麵積的函式。

  • 定義一個使用者類,要求使用者名稱和密碼不可以被訪問,只允許設定,並且密碼小於6位需要輸出相應提示並且不進行賦值要求重新賦值。

Reference

《你必須知到的.NET》





作  者:WarrenRyan
出  處:https://www.cnblogs.com/WarrenRyan/
關於作者:熱愛數學、熱愛機器學習,喜歡彈鋼琴的不知名小菜雞。
版權宣告:本文版權歸作者所有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出原文連結。若需商用,則必須聯絡作者獲得授權。
特此宣告:所有評論和私信都會在第一時間回覆。也歡迎園子的大大們指正錯誤,共同進步。或者直接私信
聲援博主:如果您覺得文章對您有幫助,可以點選文章右下角推薦一下。您的鼓勵是作者堅持原創和持續寫作的最大動力!


博主一些其他平臺:
微信公眾號:寤言不寐
BiBili——小陳的學習記錄
Github——StevenEco
BiBili——記錄學習的小陳(計算機考研紀實)
掘金——小陳的學習記錄
知乎——小陳的學習記錄

聯絡方式:

電子郵件:cxtionch@live.com

社交媒體聯絡二維碼:

.NET Core CSharp初級篇 1-3物件導向

相關文章