ref 與 out 是 C# 參數傳遞的進階機制,常讓初學者困惑。關鍵在於理解它們對值類型與引用類型的不同影響。
sbyte, byte, char, short, ushort, int, uint, long, ulong, float, double, decimal, bool 及 struct、enum。存儲數據本身。class、interface、delegate、string、object、array。存儲對堆上對象的引用 (地址)。ref 與 out 讓方法直接操作原變量,而非副本。
static void Main() {
int a = 5;
int b;
SquareRef(ref a); // a 變為 25
SquareOut(out b); // b 變為 100
Console.WriteLine($"a={a}, b={b}"); // 25, 100
}
static void SquareRef(ref int x) { x = x * x; }
static void SquareOut(out int y) { y = 10; y = y * y; } // out 參數進入方法前無需初始化,但方法內必須賦值
差異:
ref:調用前變量必須已初始化。out:調用前無需初始化,但方法內必須賦值 (確定性賦值規則)。預設傳遞引用類型時,傳遞的是引用的副本。方法內修改對象內容 會影響原對象,但將參數指向新對象 或 null 不影響外部。
加上 ref 後,方法獲得對原變量 (存儲引用的記憶體位置) 的直接訪問,可替換引用指向。
void FirstDouble(int[] arr) {
for (int i = 0; i < arr.Length; i++) arr[i] *= 2; // 修改內容:影響外部
arr = new int[] { 11, 12, 13 }; // 修改引用指向:不影響外部
}
void SecondDouble(ref int[] arr) {
for (int i = 0; i < arr.Length; i++) arr[i] *= 2;
arr = new int[] { 11, 12, 13 }; // 修改引用指向:影響外部!原變量現在指向新陣列
}

圖示:ref 讓方法訪問變量本身的地址 (如 2000),而非值的副本。

結果證明:SecondDouble(ref arr) 導致外部變量引用改變,firstArray == firstArrayCopy 為 true,secondArray == secondArrayCopy 為 false。
| 關鍵字 | 適用場景 | 調用前要求 | 方法內要求 |
|---|---|---|---|
ref | 需修改調用者變量 (值類型數值 或 引用類型指向) | 必須初始化 | 可選賦值 |
out | 方法需返回多個值 (如 TryParse 模式) | 無需初始化 | 必須賦值 |
最佳實踐:out 用於多返回值;ref 用於需修改調用者變量引用的罕見場景。日常開發中,優先考慮返回值或封裝類。