# 一起學 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的當中

> 圖片來源:[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>