C# 中有三種傳遞參數的方法:
- 值傳參
- 引用傳參
ref - 輸出傳參
out
值傳參
在這種方式下,當我們調用一個方法的時候,會為每一個值創建一個新的儲存位置,也就是說,實真的參數會賦值給方法中的形參,而實參和形參在程式執行的時候,使用的是兩個完全不同的內存,當形參改變的時候,不會影響實參的數據,從而保証了實參數據的安全。
- 參數傳遞的默認方式
- 為每個值參數創建一個新的儲存位置
- 當形參的值發生改變時,不會影響實參的值,實參數據安全
以下程式碼,進行x,y的值交換,形參的值改變了,a和b沒有發生變化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
static void Swap(int x, int y) {
int temp;
temp = x;
x = y;
y = temp;
}
static void Main(string[] args)
{
int a = 100;
int b = 500;
Swap(a, b);
Console.WriteLine($"a: {a}");
Console.WriteLine($"b: {b}");
Console.Read();
}
輸出:a:100, b:500
引用傳參 ref
若我們把方法中的形參加上 ref(reference)(引用的意思)呢?
參數的傳遞方式就從真實的數據複製,轉變為了內存地址的引用了。ref這詞,就有一點點類似C++中的 pointer的意思。
調用方法的時,同樣要在參數中標明 ref這個關鍵字,表示引用變量的內存地址。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
static void Swap(ref int x, ref int y) {
int temp;
temp = x;
x = y;
y = temp;
}
static void Main(string[] args)
{
int a = 100;
int b = 500;
Swap(ref a, ref b);
Console.WriteLine($"a: {a}");
Console.WriteLine($"b: {b}");
Console.Read();
}
輸出:a:500, b:100
輸出傳參 out
我們還可以使用輸出參數,在不改變方法的範圍內,輸出更多的數據。比如說,我們現在創建一個沒有返回值的方法:
這方法什麼事都沒幹,只是把傳入的值改成5而己,調用它時也不會有任何改變
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
static void GetValue(int x) {
x = 5;
}
static void Main(string[] args)
{
int a = 100;
int b = 500;
Swap(ref a, ref b);
Console.WriteLine($"a: {a}");
Console.WriteLine($"b: {b}");
GetValue(a);//a依然是100
Console.WriteLine($"第二次 a: {a}");
Console.Read();
}
如果我們在方法中的參數前加上out,在調用方法的時候,同時使用關鍵字out,那麼這個方法中的x值就會突破限制,直接向參數a進行輸出,a 的數據也會變成5,這個就是「輸出傳參」,就是可以把方法內部的變化,輸出反映在參數中,並且以return 以外的形式來輸出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
static void GetValue(out int x) {
x = 5;
}
static void Swap(ref int x, ref int y) {
int temp;
temp = x;
x = y;
y = temp;
}
static void Main(string[] args)
{
int a = 100;
int b = 500;
Swap(ref a, ref b);
Console.WriteLine($"a: {a}");
Console.WriteLine($"b: {b}");
GetValue(out a); //加上out,a=5
Console.WriteLine($"第二次 a: {a}");
Console.Read();
}
引用傳參 vs 輸出傳參
Q:「引用傳參ref」和「輸出傳參out」到底有什麼不同呢?
簡單一句話:使用ref需要提前定義、提前初始化、提前賦值,而使用out則沒有限制。
Q:什麼意思呢?
來改一下程式碼,把變量a初始化數據刪掉:
1
2
3
4
5
6
7
8
9
10
11
12
13
static void Main(string[] args)
{
int a;
int b = 500;
Swap(ref a, ref b);//a報錯
Console.WriteLine($"a: {a}");
Console.WriteLine($"b: {b}");
GetValue(out a);//a沒報錯
Console.WriteLine($"第二次 a: {a}");
Console.Read();
}
這時候發現問題沒,使用「引用傳參ref」的swap 方法報錯了,使用「輸出傳參out」的getValue則沒有任何問題。
所以使用「引用傳參ref」的前提就是:被引用的變量必須已經完成了初始化,也就是說,被引用變量必須得有數據。
而「輸出傳參out」則沒有這個要求,沒有初始化的變量,也可以通過輸出參數在引用的同時完成初始化。