C#中的結構體與類的區別

來源:互聯網
上載者:User

標籤:style   blog   http   color   使用   ar   strong   資料   div   

經常聽到有朋友在討論C#中的結構與類有什麼區別.正好這幾日閑來無事,自己總結一下,希望大家指點.

1. 首先是文法定義上的區別啦,這個就不用多說了.定義類使用關鍵字class 定義結構使用關鍵字struct.在文法上其實類和結構有著很多相似的地方.

   定義類的文法    

 1 class Person 2 { 3    private string name; 4    private int age; 5     6    public void SayHi() 7    { 8        Console.WriteLine("Hello,My Name is "+this.name+",My Age is "+this.age); 9    }10 }

    定義結構的文法. 

 1     struct Rectangle 2     { 3         private int width; 4         private int height; 5           6         public int GetArea() 7         { 8             return this.width * height; 9         }10     }

    從文法上來看.它們的文法都大同小異,類裡面的成員幾乎都可以定義在結構體中,但是解構函式除外.這是為什麼呢?後面解答.

2. 雖然我們說它們的文法極其相似,但是它們在文法還是有幾點區別的.

   a.在結構體中可以聲明欄位,但是聲明欄位的時候是不能給初始值的.所以當我們試圖這樣寫代碼的時候,C#編譯器在將原始碼編譯成程式集的是會提示法錯誤.

       

   我們知道如果我們在類中聲明1個欄位的同時給這個欄位賦初始值,這樣是可以滴,就像下面這樣. 

class Person{   private string name ="jack";}

    但是如果像下面這樣確實不行滴.聲明完1個欄位,再為這個欄位賦值,就像下面這樣. 

1 class Person2 {3    private string name;4    name="jack";5 }

 

    所以我們說,在類下面只能直接定義類的成員,只能定義.  比如定義成員欄位,屬性 方法 建構函式等等.上面那樣的代碼name="jack"這樣的代碼我們稱之為“執行代碼”,意思就是說這些代碼只有在被執行的時候才會有效果.而你試想一 下,那麼這些代碼什麼時候被執行呢? 建立類的對象的時候? 那還用得著建構函式嗎? 經常看到一些初學者在類的下面直接寫這樣代碼.

 

    但是又有人會說了.誒, 那麼為什麼在聲明類的欄位的時候可以賦值呢?賦值運算式也是1個執行代碼啊?為什麼這樣就不報錯呢?給你看看下面的代碼 你就會知道其中的真相了.

     

     當我們使用C#編譯器將這段代碼編譯為程式集的時候,看看微軟為我們產生的程式碼吧.

     

     展開建構函式,看看這裡面有什麼蹊蹺吧!

     

     是的,C#編譯器在編譯的時候,如果我們聲明欄位的時候為欄位賦值,那麼為欄位賦值的代碼C#編譯器在編譯的時候會將賦值的代碼放到建構函式中去,其實嚴格意義上來說,類的欄位也是不能有初始值的.只不過微軟在背後幫我們做了點事情,我們不知道而已.

     所以,不管在類和結構中,執行代碼一定要寫在方法中.不能直接寫在結構或者類的下面.因為當執行代碼寫在方法中了,那麼這些執行代碼的執行時機才可以確定,就是這個方法被調用的時候了.

    從上面的內容,我們可以看出.其實從本質上來說,類和結構的欄位都是不能有初始值的.只不過微軟在文法上允許我們在定義類的欄位的時候為其賦值.但是背後 微軟其實是把賦值的執行代碼放到建構函式中去執行的. 而結構體微軟卻不幫我們這樣做.至於這其中是什麼原因.查了些資料,也看了園子裡其他博友的文章,感覺都不能說服我,但是自己也想不出1個確切的理由微軟 為什麼要這樣做.那就先放著吧,希望參透其中原理的童鞋能指點.

 

    b. 關於建構函式.

    首先,關於隱式建構函式.我們知道,在1個類中如果我們沒有為類寫任意的建構函式,那麼C#編譯器在編譯的時候會自動的為這個類產生1個無參數的構造函 數.我們將這個建構函式稱之為隱式建構函式 但是一旦我們為這個類寫了任意的1個建構函式的時候,這個隱式的建構函式就不會自動產生了.

    在結構中,就不是這樣了,在結構中隱式的建構函式無論如何都存在.看看代碼吧.

    在下面的代碼中 我們為結構體寫了1個帶參數的建構函式.如下.

    

    我們使用new關鍵字來建立結構體對象,我們發現調用建構函式的時候,提示是有兩個建構函式的.多了1個無參數的建構函式.

     

   那麼 我們再想,能不能手動的寫1個無參數的建構函式呢?我們懷著無比激動的心情,試一下.

   

  結果是華麗麗的報錯了.所以我們得出結論. 隱式的無參數的建構函式在結構中無論如何都是存在的,所以程式員不能手動的為結構添加1個無參數的建構函式.

  關於建構函式當然還不僅僅如此.我們知道在類的建構函式中我們可以寫一些任意的代碼(前提是符合C#文法啦),在結構體的建構函式中雖然也可以寫任意的代碼.但是C#文法規定在結構體的建構函式中,必須要為結構體的所有欄位賦值.看看下面的代碼吧.

   

   啊哦.....報錯了.....

   我們也知道,在結構中還可以定義屬性,所以有童鞋就這樣寫啦.看下面代碼.

   

   這個錯誤,仍然提示我們在建構函式中沒有為所有的欄位賦值,這是很多童鞋遇到的問題,誒,不是要在建構函式中為所有的欄位賦值麼?我現在賦值了啊。為什 麼還是提示沒有賦值呢? 我們在建構函式中為屬性賦值 而屬性又為欄位賦值,為什麼這樣就不行呢? 原因很簡單.因為文法要求我們為所有的欄位賦值,雖然這裡我們看得出來為屬性賦值其實屬性再把值賦值給欄位, 我們說屬性是對欄位的操作,但是一定是這樣的嗎?我們完全可以在屬性的set塊裡面什麼都不寫,如果什麼都不寫,那麼屬性還是在操作欄位嗎? 所以屬性不一定是在操作欄位的,在結構體的建構函式中我們為屬性賦值,不認為是在對欄位賦值,所以我們在建構函式中要直接為欄位賦值.

  c.建立結構體對象的方式.

   建立結構體對象可以不使用new關鍵字.直接聲明1個變數就可以.但是這樣的話,結構體對象中的欄位是沒有初始值的,所以在使用欄位之前必須要為這個欄位賦值.

   

   原因很簡單.因為聲明的時候就不能給初始值,雖然建構函式中為對象的欄位賦值,但是此種方式建立結構體對象,沒有調用建構函式,所以必須要程式員在使用之前手動賦值。下面這樣就可以了.

   

  另外1種建立結構體對象的方式和類一樣,使用new關鍵字來建立,與不使用new關鍵字建立不同的是,通過使用new關鍵字建立結構體對象後,這個結構體 對象的欄位就已經有值了.原因不難理解,new關鍵字調用了建構函式,而結構體建構函式要求必須要為所有的欄位賦值.

  

  所以,我們不難猜出.結構體的無參數的建構函式做了什麼事情,在無參數的建構函式中為所有的欄位賦值,實值型別的欄位賦值0,給參考型別的欄位賦值null.

  d. 結構體不能從另外1個結構或者類繼承,但是可以實現介面.特殊的是.雖然結構不能從別的類或者結構繼承,但是所有的結構都預設從ValueType類繼承,ValueType類再從Object類繼承.所以結構體對象仍然擁有超類Object的成員.看看下面的微軟產生的程式碼就知道了.

    

3. 它們之間最大的區別 是結構體是實值型別 類是參考型別.

   結構體是實值型別,當其作為1個局部變數的時候,變數是儲存在棧空間中的,其對象的欄位直接儲存在這個變數中的.就像下面這樣.

   

   與參考型別的類不一樣,參考型別的變數中儲存的是對象在堆空間中的地址,所以當我們傳遞1個參考型別的變數的時候,其實傳遞的是變數的值(對象的地址) 傳遞完以後 對變數的修改會影響到另外1個變數指向的對象的值.

 

4. 最後 談一下什麼時候使用結構,什麼使用類.

   我們知道,結構儲存在棧中,而棧有1個特點,就是空間較小,但是訪問速度較快,堆空間較大,但是訪問速度相對較慢.所以當我們描述1個輕量級對象的時 候,可以將其定義為結構來提高效率.比如點,矩形,顏色,這些對象是輕量級的對象,因為描述他們,只需要少量的欄位。當描述1個重量級對象的時候,我們知 道類的對象是儲存在堆空間中的,我們就將重量級對象定義為類. 他們都表示可以包含資料成員和函數成員的資料結構。與類不同的是,結構是實值型別並且不需要堆分配。結構類型的變數直接包含結構的資料,而類類型的變數包含 對資料的引用(該變數稱為對象)。 struct 類型適合表示如點、矩形和顏色這樣的輕量對象。儘管可能將一個點表示為類,但結構在某些方案中更有效。在一些情況下,結構的成本較低。例如,如果聲明一個 含有 1000 個點對象的數組,則將為引用每個對象分配附加的記憶體。所以結構適合表示1個輕量級對象.

   基於另外1個理由我也會使用結構. 我們在變數傳值的時候,我就是希望傳遞對象的拷貝,而不是對象的引用地址,那麼這個時候也可以使用結構了.

 

  以上只是個人總結,難免會有些地方有瑕疵,歡迎大家指正,謝謝.!

C#中的結構體與類的區別

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.