| 特性 | ref | out |
|---|---|---|
| 呼叫前是否需初始化 | ✅ 必須已賦值 | ❌ 不需初始化 |
| 方法內是否必須賦值 | ❌ 可讀可寫,可不修改 | ✅ 必須在所有路徑賦值 |
| 語意 | 傳遞變數參考(雙向) | 單向輸出參數 |
| 適用場景 | 需修改呼叫端變數、或避免大型結構體複製 | 方法需回傳多個值(TryParse 模式) |
using System;
class RefOutDemo {
// out:離開方法前必須對所有 out 參數賦值
static void OutTest(out int x, out int y) {
// x = y; // 錯誤:out 參數進入方法視為未初始化,不可讀取
x = 1;
y = 2; // 必須賦值
}
// ref:進入方法前必須已初始化,方法內可讀可寫
static void RefTest(ref int x, ref int y) {
x = 1;
y = x; // 合法:可讀取 ref 參數
}
static void Main() {
// out 測試
int a, b;
OutTest(out a, out b); // 未初始化也可
Console.WriteLine($"a={a}, b={b}"); // 1, 2
int c = 11, d = 22;
OutTest(out c, out d); // 已初始化會被覆蓋
Console.WriteLine($"c={c}, d={d}"); // 1, 2
// ref 測試
// int m, n; RefTest(ref m, ref n); // 編譯錯誤:未初始化
int o = 11, p = 22;
RefTest(ref o, ref p);
Console.WriteLine($"o={o}, p={p}"); // 1, 1
}
}
out var 內嵌宣告:OutTest(out var x, out var y);struct,ref 可避免複製;但濫用會降低可讀性。ref 共享同一記憶體位置,需注意競爭條件。async)、迭代器(yield return)。ref = 雙向通道(要先有值,可改可不改)
out = 單向出口(進來沒值,出去必須有值)