細分起來,在C#中參數傳遞應該是算有四種情況的。參數傳遞方式有按值傳遞和按引用傳遞兩種,而C#支持的類型呢,也分為兩種:值類型和引用類型。所以排列組合一下,就有四種情況了:值類型按值傳遞、引用類型按值傳遞、值類型按引用傳遞和引用類型按引用傳遞。
1. 值類型按值傳遞
值類型變量是直接包含其數據,而引用類型包含的是對數據的引用(即數據的地址)。因此對於值類型變量按值傳遞時,傳遞的是變量的一個副本。方法內發生的對參數的更改對原變量中存儲的原數據無任何影響,只會影響到變量的副本。
我們用段示例代碼來解釋。

1 static void Main(string[] args) 2 { 3 var number = 14; 4 5 Console.WriteLine( 6 string.Format("Inside main method.before calling [ChangeValueByValue] method, value is {0}", 7 number.ToString())); 8 ChangeValueByValue(number); 9 Console.WriteLine(string.Format( 10 "Inside main method.after calling [ChangeValueByValue] method, value is {0}", number.ToString())); 11 Console.ReadLine(); 12 } 13 14 static void ChangeValueByValue(int number) 15 { 16 number = 23; 17 }
- number變量賦值為14.
- 執行方法ChangeValueByValue時,傳遞number變量的副本給方法,假設變量copynumber為該副本,則其初始值和number一樣,也為14。
- 方法內修改number的值為23,其實是修改number的副本,所以copynumber的值被修改為23。而number的值保持14不變。
執行結果如下:
2. 值類型按引用傳遞
值類型按引用傳遞向方法傳遞的是變量的地址,因此在方法內對變量的任何改變都會影響到原數據。必須使用ref或out關鍵字來傳遞變量。下面的示例使用ref來說明。
1 static void Main(string[] args) 2 { 3 var number = 14; 4 5 Console.WriteLine(string.Format("Inside main method.before calling [ChangeValueByRef] method, value is {0}", number.ToString())); 6 ChangeValueByRef(ref number); 7 Console.WriteLine(string.Format("Inside main method.after calling [ChangeValueByRef] method, value is {0}", number.ToString())); 8 Console.ReadLine(); 9 } 10 11 static void ChangeValueByRef(ref int number) 12 { 13 number = 234; 14 }
- number變量賦值為14
- 執行方法ChangeValueByRef時,傳遞變量number的地址(59997)到方法內,假設為copynumberaddress存放的是number變量的地址14,其實個人覺得這里應該是number變量地址的副本傳遞給了方法
- 方法內修改number值為234,也即對地址59997存放的數據進行修改為234。所以number的值也會變成234
執行結果如下:
3. 引用類型按值傳遞
引用類型按值傳遞和值類型按引用傳遞在某種程度上具有相同的行為。引用類型按值傳遞是向方法內傳遞變量地址的副本,因此對該變量的數據的修改會直接影響到原數據(注意是對數據的修改,其他修改是不會影響到原數據的,比如你在方法內,將對象指向一個同類型的新對象,是不會影響到原數據的,因為你只是將變量地址的副本改成了新對象的地址。原數據還是指向舊的地址)。請看下面簡單示例說明:
1 static void Main(string[] args) 2 { 3 int[] array = { 54, 691, 1234 }; 4 Console.WriteLine(string.Format("Inside main method.before calling [ChangeRefByValue] method, value is {0}", array[0].ToString())); 5 ChangeRefByValue(array); 6 Console.WriteLine(string.Format("Inside main method.after calling [ChangeRefByValue] method, value is {0}", array[0].ToString())); 7 8 Console.ReadLine(); 9 } 10 11 static void ChangeRefByValue(int[] array) 12 { 13 array[0] = 98; 14 array = new int[5] { -2, -34, -12, -43, -392 }; 15 Console.WriteLine(string.Format("Inside method [ChangeRefByValue],the first element is {0}", array[0])); 16 }
- 創建一個新數組array,其第0個元素值為54
- 執行方法ChangeRefByValue,傳遞變量array地址(2000)的副本到方法內,假設copyarrayaddress存放了array地址副本
- 在方法ChangeRefByValue內,首先將array第0個元素值改為98,因為指向同樣的地址單元,因此會影響到原來數組array第0個元素的值
- 然后執行
array = new int[5] { -2, -34, -12, -43, -392 };
語句,其實是將array地址的副本copyarrayaddress指向了新數組的地址(1980),而array變量還是指向的之前的地址(2000)
執行結果如下:
4. 引用類型按引用傳遞
引用類型按引用傳遞是向方法內傳遞變量地址(注意這里不是地址副本),因此對變量的任何改變都會影響到原變量(不管是數據的改變,還是指向新的對象)。請看下面示例:
1 static void Main(string[] args) 2 { 3 int[] array = { 98, 691, 1234 }; 4 5 Console.WriteLine(string.Format("Inside main method.before calling [ChangeRefByRef] method, value is {0}", array[0].ToString())); 6 ChangeRefByRef(ref array); 7 Console.WriteLine(string.Format("Inside main method.after calling [ChangeRefByRef] method, value is {0}", array[0].ToString())); 8 9 Console.ReadLine(); 10 } 11 12 static void ChangeRefByRef(ref int[] array) 13 { 14 array[0] = 35; 15 array = new int[5] { -2, -34, -12, -43, -392 }; 16 Console.WriteLine(string.Format("Inside method [ChangeRefByValue],the first element is {0}", array[0])); 17 }
- 創建一個新數組array,其第0個元素值為98
- 指向方法ChangeRefByRef,傳遞變量array的地址(2000)到方法內
- 在方法ChangeRefByRef內,首先將array第0個元素值改為35,因為指向同樣的地址單元,因此會影響到原來數組array第0個元素的值
- 然后執行
array = new int[5] { -2, -34, -12, -43, -392 };
語句,將array指向新的數組newarray,其數組的地址也變成了新數組的地址(1980)。因此在執行方法后,array數組和newarray是相等的。
執行結果如下: