首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C# 入門教程(三):型別系統核心——值類型 vs 參考類型深度解析

     編輯:關於C語言

前言

C# 型別系統分為兩大陣營:值類型 與 參考類型。這是理解記憶體模型、參數傳遞、拷貝語義、效能特徵的基石。本文透過圖解、代碼實驗、IL 驗證,徹底釐清兩者差異、堆疊 vs 堆、傳值 vs 傳參、裝箱/拆箱、struct 設計指南。

型別分類總覽

類別包含類型儲存位置變數內容預設值
值類型簡單類型、列舉、結構、可為 null 值類型堆疊 / 內嵌於物件資料本身全 0 (false/0/null)
參考類型類別、介面、委派、陣列、字串、object、dynamic堆參考(位址)null

核心差異:資料儲存與複製語義

值類型:資料即變數


int val1 = 0;
int val2 = val1; // 複製資料位元
val2 = 123;
Console.WriteLine($"val1={val1}, val2={val2}"); // val1=0, val2=123
  • val1、val2 各自擁有獨立記憶體位置
  • 指派 = 位元逐位複製
  • 修改其中一個不影響另一個

參考類型:變數存「地址」


class CValue { public int Value = 0; }

CValue ref1 = new CValue(); // 堆上配置物件,ref1 存位址
CValue ref2 = ref1;         // 複製位址,指向同一物件
ref2.Value = 123;
Console.WriteLine($"ref1.Value={ref1.Value}, ref2.Value={ref2.Value}"); // 123, 123
  • ref1、ref2 存的是同一個物件的參考
  • 指派 = 參考複製
  • 透過任一變數修改物件內容,另一個變數觀察到相同變化
  • 變數本身 (參考) 未變,變的是被參考的物件

記憶體模型圖解


// 值類型
棧: [val1: 0]  [val2: 123]  (獨立槽位)

// 參考類型
棧: [ref1: 0x0012AB00]  [ref2: 0x0012AB00]  (相同位址)
    ↓
堆: [Object@0x0012AB00: { Value: 123, SyncBlock, TypeHandle }]

關鍵場景實驗

1. 方法參數傳遞


void ByValue(int x) { x = 10; }
void ByRefClass(CValue c) { c.Value = 20; }
void ByRefRef(ref CValue c) { c = new CValue { Value = 30 }; }

int a = 5; ByValue(a);     // a 仍為 5
CValue o1 = new CValue { Value = 1 }; ByRefClass(o1); // o1.Value 變 20
CValue o2 = new CValue { Value = 1 }; ByRefRef(ref o2); // o2 指向新物件,Value=30
  • 預設 = 傳值:值類型複製資料,參考類型複製參考
  • ref/out:傳遞變數本身的位址,可修改變數指向

2. 裝箱與拆箱


int i = 123;
object o = i;      // 裝箱:堆配置物件,複製值 → 效能成本
int j = (int)o;    // 拆箱:型別檢查,複製值回堆疊

// 避免頻繁裝箱:用泛型 List 而非 ArrayList

3. 結構 vs 類別選擇指南

特徵結構類別
語義單一值、不可變、小型 (≤16 bytes)實體、有身分識別、可變、大型
繼承不可繼承 (隱含 sealed)支援繼承、多型
建構函數無參數建構函數固定 (全 0 初始化)可自訂多載
null不可為 null (除非 Nullable<T>)可為 null
複製值語義 (深複製)參考語義 (淺複製)
效能無堆配置/GC 壓力,但大結構複製成本高堆配置、GC 管理、參考傳遞廉價

IL 驗證:值類型無物件標頭


// 類別實例物件佈局
[SyncBlockIndex] [TypeHandle] [Fields...]

// 結構/值類型:無 SyncBlock、無 TypeHandle,純資料
// 只有裝箱時才在堆上包裝成有標頭的物件

實務建議

  1. 預設用類別:除非明確需要值語義、不可變、高頻短命小物件
  2. 結構必須不可變:所有欄位 readonly、屬性唯讀、方法回傳新實例
  3. 避免大結構:>16 bytes 複製開銷超過參考傳遞
  4. 泛型消除裝箱:List、Dictionary、Action
  5. readonly struct (C# 7.2+):編譯器強制不可變、避免防禦性複製

總結

值類型 = 資料本身,複製 = 深複製;參考類型 = 資料位址,複製 = 淺複製。這一根本差異決定了參數傳遞、集合儲存、效能特徵、語義設計的一切。堆疊 vs 堆是實現細節,值 vs 參考語義才是設計核心。下一課將進入類別與物件導向程式設計:封裝、繼承、多型、介面、委派、事件。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved