Try   HackMD

一起學 Class and Struct (C#)

tags: C# Core ReferenceType/ValueType Stack/Heap

學習目標

了解ClassStruct的差異和使用時機

目錄

Class與Struct

直接說明其核心差異其實很簡單如下

  • Class 是參考類型(Reference type)
  • Struct 是實值類型(Value type)

但什麼是參考類型以及實值類型?其中又有什差異?接下是我們要是我們要了的問題

參考類型、實值類型

初步了解

C#語言中有兩個主要類別分別為

參考類型(Reference type)

  1. 關鍵字定義:class、interface、delegate、record
  2. 內建(Built-in)類型:dynamic、object、string

實值類型(Value type)

  1. 關鍵字定義:struct
  2. 內建(Built-in)類型:bool、byte、int、char等等

官方參考文件
Reference types
Value types

除了文件上面的紀錄外想要快速區分其定義也可以查看其繼承,如果有繼承System.ValueType就會是實值類型。

知道定義後接下來說說兩個之間的不同

差異比較

這邊主要透過文章Choosing Between Class and Struct來認識,以下除了整理成自己方便理解的筆記外也外加了許多參考資料。

資源配置與釋放

其資源分配和回收的方式不同如下:

  • Reference types:存放於Heap會由garbage-collected(GC)去清理
  • Value types:存放於Stack函式結束後直接釋放

這張圖清楚描述了其配置和釋放的不同,其Heap會由GC的機制下去自動釋放

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

圖片來源:Six Important .NET Concepts: Stack, Heap, Value Types, Reference Types, Boxing, and Unboxing

陣列(array)使用差異

因為其資源配置的方式進而影響array內的元素配置方式也會不相同,一般來說Value types對於配置以釋放來說所消耗的資源會更少。

記憶體配置

我們透過以下圖片來了解其儲存的差異,分別為Stack Memory和Heap Memory這邊可以看其差異,

  1. Value types:儲存時回記錄在Stack當中
  2. Reference types:會在Stack記錄Heap的位置並且將資料存放在Heap的當中

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

圖片來源:Stack Vs Heap Memory - C#

這邊需要而外提到Boxing and Unboxing之行為,其程式碼如下

int i = 123; // The following line boxes i. object o = i;
o = 123; i = (int)o; // unboxing

這樣的轉換操作會把Value types轉變成Reference types方式去做儲存,除了消失Stack儲存的好處外,過多的轉換也可能造成Heap和garbage-collected對於程序造成效能上的影響。

複製操作

因為Reference types的儲存資料的特性,在執行複製候只需要複製位址即可,至於Value types則會需要完整的複製整個數值,因此在資源花費上Reference types會更加便宜。

複製後值變更

Reference types執行複製後其位址還是指向同一份資料,因此作變更時所有指向同一個位址的資料全部都會影響。
Value types的則是完整複製,故在變更的時候不會影響任何複本,但是此行為不是由使用者定義明確的複製操作是隱含建立,可能會造成許多使用者混淆。

如何選擇

這邊直接使用官方解釋

通常有以下的狀況會考慮使用struct

  • 實例小、參數短期使用、嵌入在其它物件內

評估方式可確認是否有其特性

  • 以邏輯方式表示單一值,類似基本類型(int、double等)
  • 實例大小小於16 bytes
  • 不可變
  • 不須經常boxed

除此以外的所有情況都直接定義為Class

來源依樣同Choosing Between Class and Struct

其它差異

除了儲存方式以外在C#的設計上也有針對Struct也有些限制,因為某些限制會因為C#的版本被開放,這邊列一下目前無法還有的限制

  • 無法繼承其它類別或結構,且不能為類別的基底
  • 結構可以實作介面
  • 無法實作完成項(過去稱為解構子)

結論

整體來說最核心的差異就是儲存方式的不同,可以透過此文章Stack Vs Heap Memory - C#再去強化儲存機制上的認知,儘管使用struct的情境不多,但是有這樣的學過一輪也算是對C#有更深一步的認識,未來在實作上其概念也能更清楚。



相關參考來源:
Stack Vs Heap Memory - C#
Choosing Between Class and Struct
C# Struct 使用注意事項
結構類型的設計限制