C# 方法參數傳遞機制是開發者必須掌握的核心概念。本文系統解析值傳遞與引用傳遞的區別,並深入探討結構與類作為參數時的行為差異,配合代碼示例助你徹底釐清。
預設情況下,C# 採用值傳遞:方法接收參數的副本,修改不影響原變數。若需在方法內修改原變數,須使用 ref 或 out 關鍵字進行引用傳遞。
class Program {
static void Main(string[] args) {
int arg;
// 傳值:Main 中的 arg 不會改變
arg = 4;
SquareVal(arg);
Console.WriteLine(arg); // 輸出: 4
// 傳引用:Main 中的 arg 會被修改
arg = 4;
SquareRef(ref arg);
Console.WriteLine(arg); // 輸出: 16
}
static void SquareVal(int valParameter) {
valParameter *= valParameter; // 修改副本
}
static void SquareRef(ref int refParameter) {
refParameter *= refParameter; // 修改原變數
}
}
ref/out):傳遞變數地址,方法內修改直接反映到原變數。out 要求方法在返回前必須賦值,ref 則要求呼叫前已初始化。這是許多開發者容易混淆的地方。核心在於值類型與引用類型的語意差異。
class TheClass { public string willIChange; }
struct TheStruct { public string willIChange; }
class TestClassAndStruct {
static void ClassTaker(TheClass c) {
c.willIChange = "Changed";
}
static void StructTaker(TheStruct s) {
s.willIChange = "Changed";
}
static void Main() {
TheClass testClass = new TheClass();
TheStruct testStruct = new TheStruct();
testClass.willIChange = "Not Changed";
testStruct.willIChange = "Not Changed";
ClassTaker(testClass);
StructTaker(testStruct);
Console.WriteLine("Class field = {0}", testClass.willIChange); // Changed
Console.WriteLine("Struct field = {0}", testStruct.willIChange); // Not Changed
Console.ReadKey();
}
}
Class field = Changed
Struct field = Not Changed
| 特性 | 類 - 引用類型 | 結構 - 值類型 |
|---|---|---|
| 記憶體分配 | 堆積,變數存儲引用(地址) | 堆疊(通常),變數直接存儲資料 |
| 傳遞給方法時 | 複製「引用」(地址副本),雙方指向同一物件 | 複製「整個結構實體」,方法操作的是獨立副本 |
| 修改欄位/屬性 | 影響原物件 | 僅影響副本,原結構不變 |
| 重新指派參數變數 (c = new TheClass()) | 僅改變區域引用指向,不影響呼叫端引用 | 不適用(結構不可為 null,通常不重新指派) |
c 是 testClass 引用的副本,兩者指向同一堆積物件。修改 c.willIChange 實際修改該物件欄位,故 testClass 反映變化。s 是 testStruct 的完整副本。修改 s.willIChange 僅影響副本,方法結束副本銷毀,原 testStruct 保持不變。ref 傳遞結構,或讓方法返回新結構實例。掌握值/引用傳遞與值/引用類型的組合行為,是編寫正確、高效 C# 代碼的基石。牢記:類傳引用(地址副本),結構傳值(實體副本),即可避開 90% 的坑。