許多開發者誤以為「參考型別預設傳址、實值型別預設傳值」,實則 **所有參數預設皆為傳值(複製)**。ref/out 在 IL 層級相同(byref),差別僅在語法規則:ref 需預先指派、out 不需。本文以堆疊記憶體佈局、暫存器狀態、反組譯碼為證,徹底釐清參數傳遞機制。
void Change2(object o) { o = new object(); }
object obj = null;
Change2(obj);
Console.WriteLine(obj ?? "null"); // 輸出 null
obj 的值(參考位址)被複製給參數 o,方法內修改 o 只改變區域複本,不影響原變數。
static void Ref_Out(ref int a, out int b, int c)
{ a = 15; b = 127; c = 99; }
int i1 = -1; int i2;
Ref_Out(ref i1, out i2, i1);
// i1=15, i2=127
偵錯器觀察呼叫約定(x86):
a (ref) → EDI 存放 i1 位址 0x0012F444b (out) → ESI 存放 i2 位址 0x0012F440c (byval) → 堆疊 [EBP+8] 存放值 -1// a = 15
mov dword ptr [edi], 0Fh // 解參考 EDI 寫入
// b = 127
mov dword ptr [esi], 7Fh // 解參考 ESI 寫入
// c = 99
mov dword ptr [ebp+8], 63h // 直接覆寫堆疊複本
方法返回後,i1/i2 已被修改,c 的複本隨堆疊框架銷毀。
ref/out 複製的是**變數位址**(Managed Pointer),方法內解參考即可修改原變數;