iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 24
1
Modern Web

C#與ASP.Net入門-我要成為工程師!!系列 第 24

Day24-C#-參數的傳遞方式-Call By Value/Call By Reference/Output parameter

當使用return敘述時,一次只能傳回一個值或不傳回值返回原呼叫處。若方法A某個敘述呼叫方法B時,需要一次能傳回2個以上的值時,必須使用參考呼叫或傳出參數來達成。

本文將介紹方法中引數的傳遞方式,有以下三種:

1. 傳值呼叫Call By Value
2. 參考呼叫Call By Reference
3. 傳出參數Output parameter

=================================================================

實質型別 VS 參考型別

先來複習一下Day06介紹到的內容

  • 實質型別(Value Type):
    變數的記憶體空間存放的是實際的值。如 int x=5,x的內容就是5。
    實質型別有:簡單型別(帶/不帶正負號的整數、浮點數、字元、布林值)、列舉型別、結構型別、可為Null的實質型別。
    傳遞方式:Call By Value、Call By Reference、Output parameter

  • 參考型別(Reference Type):
    變數的記憶體空間存放的是值的記憶體位置,也就是放值的記憶體第一個開頭的地方。如int[] A = new int[] {1,4,2}。A存的就是[1,4,2]的記憶體位置。當要讀取4的時候,就是讀取A[1]→A記憶體位置的第二個值。
    註:陣列的第一個位置編號從0開始
    參考型別有:類別(物件、字串、自訂類別)、介面型別、陣列、委派型別。
    傳遞方式:Call By Reference、Output parameter

=================================================================

傳值呼叫Call By Value

傳值呼叫為C#實質型別預設的方式。傳遞參數時,傳遞方(呼叫方法)會將實際參數(actual parameter)複製一份給接收方(被呼叫方法),複製參數稱為虛擬參數(formal parameter),實際參數和虛擬參數各佔據不同的記憶體位置。所以當被呼叫方法內的虛擬參數被修改,並不會影響實際參數。這種方式適用於希望方法內的結果不影響方法外的變數時使用,可以保護變數不被修改。

static void Main(string[] args)
{ 
    int money =1000;
    int newAmount = addMoney(money);//呼叫addMoney的方法並賦值給newAmount
    Console.WriteLine(money);//amount的值不會改變
    Console.WriteLine(newAmount);
    Console.ReadKey();
}
 
private static int addMoney(int amount)
{
    amount = amount * 2;
    return amount;
}

https://ithelp.ithome.com.tw/upload/images/20190925/20120055xf3CtEk4ZW.png
https://ithelp.ithome.com.tw/upload/images/20190923/20120055HWNd0PWYMG.png

=================================================================

參考呼叫Call By Reference

參考呼叫則是傳遞參數記憶體的位置給接收方,由於是同一個記憶體位置,所以變動的都是同一個記憶體位置的值,彼此會互相影響。
參考型別以這個為傳遞方式,有沒有加ref不影響,但實際參數及虛擬參數要一起加或一起不加喔~實質型別操作方法為將實際參數及虛擬參數宣告為ref,即成為參考呼叫。
ref宣告的實際參數必須是變數、陣列或物件,不可為常數或運算式。且實際參數必須初始化後才能使用。

static void Main(string[] args)
{ 
    int money =1000;
    int newAmount = addMoney(ref money);//加上ref
    Console.WriteLine(money);
    Console.WriteLine(newAmount);
    Console.ReadKey();
}
 
private static int addMoney(ref int amount)//加上ref
{
    amount = amount * 2;
    return amount;
}

https://ithelp.ithome.com.tw/upload/images/20190925/20120055hoaWLmDQt7.png
https://ithelp.ithome.com.tw/upload/images/20190923/20120055E4TTQCeian.png

=================================================================

傳出參數Output parameter

傳出參數與參考呼叫的實際參數和虛擬參數都是佔用相同記憶體位置,最大差異為傳出參數的實際參數不必設定初始化即可傳遞,不過需要先指派值給被呼叫的方法,方法才能傳回。操作方法為將實際參數及虛擬參數前方加上out。常用在想傳回多個回傳值時。

static void Main(string[] args)
{ 
   int money;//不用先初始化
   int bonus;
   int newAmount = addMoney(out money,out bonus);
   Console.WriteLine(money);
   Console.WriteLine(bonus);
   Console.WriteLine(newAmount);
   Console.ReadKey();
}
 
private static int addMoney(out int amount, out int bonus)
{
    amount = 1000;//amount需要先指派值
    bonus = 2 * amount;// bonus需要先指派值
    int total;
    total = amount + bonus;
    return total;
}

C#6及舊版中,必須先在其他陳述式中宣告變數,再將它傳遞為 out 引數

int money =1000;
int newAmount = addMoney(out money);

C#7起,可以在方法呼叫的引數清單中宣告out變數,可避免不小心在方法呼叫前先將值指派給變數。

int newAmount = addMoney(out int money);

https://ithelp.ithome.com.tw/upload/images/20190925/20120055wev3vm30i0.png

=================================================================

參考資料

MSDN-傳遞參考類型的參數
MSDN-out 參數修飾詞
MSDN-ref
[轉載]C# - 函數call by value/reference
C# 傳值Call by value、參考Call by Reference 與相等比較
【C#】ref與out // 傳值與傳址
書籍:
Visual C# 2017程式設計經典
從零開始學Visual C# 2015程式設計


上一篇
Day23-C#-傳說中的static!!!靜態類別和靜態類別成員
下一篇
Day25-C#-凡事都可能有例外~出其不意就是人森阿(´_ゝ`)(例外處理try-catch)
系列文
C#與ASP.Net入門-我要成為工程師!!31

1 則留言

0
小朱
iT邦新手 4 級 ‧ 2019-09-25 23:15:39

實值型別和參考型別最簡單的分法就是衍生自 System.ValueType 的都是實值型別,.NET Framework 內的基本型態都是struct,而struct就是System.ValueType的代表字;不是衍生自 System.ValueType的類別就都是參考型別。

https://docs.microsoft.com/en-us/dotnet/api/system.valuetype

參考型別作為參數時預設就是 ref,若有加 ref 也不會影響其性質。

另外,Call By Reference 程式碼的註解有誤,money變數是會被改變的 (輸出結果也是如此)。

感謝大大補充!註解處已修改~

我要留言

立即登入留言