new 是 C# 中最常用卻最容易被誤解的關鍵字。它同時扮演運算符(建立物件)、修飾符(隱藏繼承成員)、泛型約束(要求無參數建構函式)三種角色。本文將透過 IL 反編譯與記憶體模型,徹底揭開 new 背後的運作機制。
| 角色 | 用途 | 關鍵規則 |
|---|---|---|
| 運算符 | 配置記憶體、呼叫建構函式、回傳參考 | 不可重載;失敗拋 OutOfMemoryException |
| 修飾符 | 隱藏基類同名成員(需基類標記 virtual) |
不可與 override 共存;可用 base 存取被隱藏成員 |
| 泛型約束 | where T : new() 限定型別參數必須有 public 無參建構函式 |
多約束時必須置於最後 |
測試程式碼:
int i; // 未初始化
int j = new int(); // 初始化為 0
MyClass mClass = new MyClass(123); // 參考類型
MyStruct mStruct = new MyStruct("My Struct"); // 值類型
IL 反編譯關鍵片段:
// int j = new int();
L_0001: ldc.i4.0
L_0002: stloc.1
// MyClass mClass = new MyClass(123);
L_0003: ldc.i4.s 0x7b
L_0005: newobj instance void MyClass::.ctor(int32) // 配置堆記憶體 + 呼叫 ctor
L_000a: stloc.2
// MyStruct mStruct = new MyStruct("My Struct");
L_000b: ldloca.s struct2 // 取區域變數位址
L_000d: ldstr "My Struct"
L_0012: call instance void MyStruct::.ctor(string) // 僅呼叫 ctor,堆疊上直接初始化
L_0017: nop
| 操作 | 記憶體行為 | GC 管理 |
|---|---|---|
new Class() |
託管堆配置物件,堆疊存參考 | 受 GC 管理 |
new Struct() |
堆疊直接配置實例資料(或內聯於物件) | 不受 GC 管理 |
new int() / new bool() |
堆疊配置並零初始化 | 不受 GC 管理 |
new string('*', 100)、new string(new char[]{'a','b','c'}) 比手寫字串字面值更清晰、效能更佳int i vs int i = new int():前者未初始化(區域變數需明確賦值才能使用),後者保證為 0new 運算符不可重載,這是語言層面的硬性規定new T() 要求 T 有 public 無參建構函式,否則編譯錯誤從 IL 指令 newobj(參考類型)與 call .ctor(值類型)的差異,到記憶體模型的本質區別,new 的三重身份終於被「說透」。下次再見到 new,你將知道它背後發生的每一步。