---
# System prepended metadata

title: 一起學 Class and Struct (C#)
tags: [Core, Stack/Heap, C#, ReferenceType/ValueType]

---

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