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

C# 方法參數四大類型深度解析:值、ref、out、params

     編輯:關於C語言

核心概念:參數傳遞機制

C# 方法參數預設為「值傳遞」。理解四種修飾詞的語意差異,是撰寫正確、高效程式碼的關鍵。

對照表

類型關鍵字記憶體行為呼叫端要求被呼叫端要求典型用途
值參數(無)複製實參值到形參 (值型別複製內容,參考型別複製參考)需初始化可讀寫形參,不影響實參 (值型別)預設、單向輸入
參考參數ref傳遞實參的記憶體位址,形參別名指向同一儲存位置必須初始化可讀寫,變更直接反映實參雙向傳遞、修改呼叫端變數、避免大型結構體複製
輸出參數out同 ref,但語意為「僅輸出」無需初始化方法返回前必須指派多返回值、TryParse 模式
參數陣列params將零到多個引數封裝為陣列傳遞可傳 0~N 個引數或單一陣列內部視為陣列 T[]可變參數列表、String.Format, Console.WriteLine

程式碼範例

1. 值參數 (預設)

void Increment(int x) { x++; } // 只改變區域副本
int a = 5;
Increment(a);
Console.WriteLine(a); // 5,未變

2. ref 參考參數

void Swap(ref int x, ref int y)
{
    int t = x; x = y; y = t;
}
int a = 1, b = 2;
Swap(ref a, ref b);
Console.WriteLine($"{a}, {b}"); // 2, 1

// 結構體避免複製
struct LargeStruct { public long L1, L2, L3, L4; }
void Modify(ref LargeStruct s) { s.L1 = 99; } // 不複製 32 bytes

3. out 輸出參數

// 標準 TryParse 模式
bool TryParseInt(string s, out int result)
{
    return int.TryParse(s, out result); // 必須指派 result
}

int num;
if (TryParseInt("123", out num)) Console.WriteLine(num); // 123
// num 呼叫前可未初始化

4. params 參數陣列

void PrintAll(params object[] args)
{
    Console.WriteLine($"Count: {args.Length}");
    foreach (var o in args) Console.Write(o + " ");
    Console.WriteLine();
}

PrintAll();                    // Count: 0
PrintAll(1, 2, 3);             // Count: 3
PrintAll("A", "B", "C", "D");  // Count: 4
PrintAll(new object[] { 1, 2 }); // Count: 2 (傳陣列)

進階規則與陷阱

1. 參考型別的「值傳遞」vs「ref 傳遞」

class Person { public string Name; }

void ChangeName(Person p) { p.Name = "Bob"; }      // 修改物件內容 ✅
void ReplacePerson(Person p) { p = new Person(); } // 只換區域參考 ❌ 不影響實參

void ReplacePersonRef(ref Person p) { p = new Person(); } // 換掉實參指向 ✅

2. 多載解析優先序

void M(int x) { }           // 1. 精確匹配
void M(params int[] x) { }  // 2. params 擴展匹配
void M(ref int x) { }       // 僅當呼叫端加 ref 才匹配

M(5);       // 呼叫 (1)
M(1,2,3);   // 呼叫 (2)
int i=0; M(ref i); // 呼叫 (3)

3. params 限制

  • 每個方法最多一個 params 參數,且必須是最後一個參數。
  • 不可與 ref/out 共存:params ref int[] ❌。
  • 效能:每次呼叫會配置陣列物件;熱路徑可提供非 params 多載 (如 void Log(string msg) + void Log(string fmt, params object[] args))。

4. C# 7.2+ in 修飾詞 (補充)

// 唯讀參考傳遞:避免複製大型結構體,且禁止方法內修改
void ReadOnly(in LargeStruct s)
{
    // s.L1 = 10; // 編譯錯誤:無法指派唯讀變數
    Console.WriteLine(s.L1);
}

最佳實踐建議

  1. **預設用值參數** (不可變型別、小型結構體)。
  2. **需修改呼叫端變數** → ref (輸入輸出) 或 out (純輸出)。
  3. **多返回值** → 優先用 out 或 ValueTuple ((bool, int)) / 自訂 Result<T>。
  4. **可變引數** → params 簡化呼叫端;效能敏感處提供陣列多載。
  5. **大型結構體唯讀傳遞** → in (C# 7.2+),兼顧效能與安全。
  6. **避免** 在非必要場合濫用 ref/out,增加認知負擔與副作用風險。

精準選擇參數模式,能讓方法契約更清晰、執行效率更優、Bug 更少。

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