# 一起學 Class and Struct (C#) ###### tags: `C#` `Core` `ReferenceType/ValueType` `Stack/Heap` ## 學習目標 了解`Class`和`Struct`的差異和使用時機 ## 目錄 [TOC] # Class與Struct 直接說明其核心差異其實很簡單如下 * Class 是參考類型(Reference type) * Struct 是實值類型(Value type) 但什麼是<font class="red">**參考類型**</font>以及<font class="red">**實值類型**</font>?其中又有什差異?接下是我們要是我們要了的問題 # 參考類型、實值類型 ## 初步了解 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](https://docs.microsoft.com/bs-latn-ba/dotnet/csharp/language-reference/keywords/reference-types) > [Value types](https://docs.microsoft.com/bs-latn-ba/dotnet/csharp/language-reference/builtin-types/value-types) 除了文件上面的紀錄外想要快速區分其定義也可以查看其繼承,如果有繼承[System.ValueType](https://docs.microsoft.com/en-us/dotnet/api/system.valuetype?redirectedfrom=MSDN&view=net-6.0)就會是實值類型。 知道定義後接下來說說兩個之間的不同 ## 差異比較 這邊主要透過文章[Choosing Between Class and Struct](https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/choosing-between-class-and-struct)來認識,以下除了整理成自己方便理解的筆記外也外加了許多參考資料。 ### 資源配置與釋放 其資源分配和回收的方式不同如下: * Reference types:存放於Heap會由garbage-collected(GC)去清理 * Value types:存放於Stack函式結束後直接釋放 這張圖清楚描述了其配置和釋放的不同,其Heap會由GC的機制下去自動釋放 <img src="https://www.codeproject.com/KB/Articles/6importentStepsDotNet/13.jpg"/> > 圖片來源:[Six Important .NET Concepts: Stack, Heap, Value Types, Reference Types, Boxing, and Unboxing](https://www.codeproject.com/Articles/76153/Six-important-NET-concepts-Stack-heap-value-types#Stack%20and%20Heap) ### 陣列(array)使用差異 因為其資源配置的方式進而影響array內的元素配置方式也會不相同,一般來說Value types對於配置以釋放來說所消耗的資源會更少。 ### 記憶體配置 我們透過以下圖片來了解其儲存的差異,分別為Stack Memory和Heap Memory這邊可以看其差異, 1. Value types:儲存時回記錄在Stack當中 2. Reference types:會在Stack記錄Heap的位置並且將資料存放在Heap的當中 ![](https://i.imgur.com/OvMQ8h5.png) > 圖片來源:[Stack Vs Heap Memory - C#](https://www.c-sharpcorner.com/article/stack-vs-heap-memory-c-sharp/) 這邊需要而外提到[Boxing and Unboxing](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/types/boxing-and-unboxing)之行為,其程式碼如下 ```csharp= int i = 123; // The following line boxes i. object o = i; ``` ```csharp= o = 123; i = (int)o; // unboxing ``` 這樣的轉換操作會把Value types轉變成Reference types方式去做儲存,除了消失Stack儲存的好處外,過多的轉換也可能造成Heap和garbage-collected對於程序造成效能上的影響。 ## 複製操作 因為Reference types的儲存資料的特性,在執行複製候只需要複製位址即可,至於Value types則會需要完整的複製整個數值,因此在資源花費上Reference types會更加便宜。 ## 複製後值變更 Reference types執行複製後其位址還是指向同一份資料,因此作變更時所有指向同一個位址的資料全部都會影響。 Value types的則是完整複製,故在變更的時候不會影響任何複本,但是此行為不是由使用者定義明確的複製操作是<font class="red">**隱含建立**</font>,可能會造成許多使用者混淆。 # 如何選擇 這邊直接使用官方解釋 通常有以下的狀況會考慮使用`struct` * 實例小、參數短期使用、嵌入在其它物件內 評估方式可確認是否有其特性 * 以邏輯方式表示單一值,類似基本類型(int、double...等) * 實例大小小於16 bytes * 不可變 * 不須經常boxed **除此以外的所有情況都直接定義為Class** > 來源依樣同[Choosing Between Class and Struct](https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/choosing-between-class-and-struct) # 其它差異 除了儲存方式以外在C#的設計上也有針對`Struct`也有些限制,因為某些限制會因為C#的版本被開放,這邊列一下目前無法還有的限制 * 無法繼承其它類別或結構,且不能為類別的基底 * 結構可以實作介面 * 無法實作完成項(過去稱為**解構子**) # 結論 整體來說最核心的差異就是儲存方式的不同,可以透過此文章[Stack Vs Heap Memory - C#](https://www.c-sharpcorner.com/article/stack-vs-heap-memory-c-sharp/)再去強化儲存機制上的認知,儘管使用`struct`的情境不多,但是有這樣的學過一輪也算是對C#有更深一步的認識,未來在實作上其概念也能更清楚。 <br/> --- 相關參考來源: [Stack Vs Heap Memory - C#](https://www.c-sharpcorner.com/article/stack-vs-heap-memory-c-sharp/) [Choosing Between Class and Struct](https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/choosing-between-class-and-struct) [C# Struct 使用注意事項](https://blog.opasschang.com/csharp-struct-usage-notes/) [結構類型的設計限制](https://docs.microsoft.com/zh-tw/dotnet/csharp/language-reference/builtin-types/struct#limitations-with-the-design-of-a-structure-type) <style> .red{color: red;} </style>