C#程式設計引用型別和值型別 以及引用傳遞和值傳遞

yesye發表於2021-09-09

我們從最簡單的說起(基礎知識,懂的同學直接往下拉),直接上程式碼:

static int amount;
static void AddTV(int amount)
{
    amount++;
    Console.WriteLine("方法中,amount="+amount);
}

然後,我們將引數amout傳入AddTV()方法,希望能讓其+1

amount = 10;
AddTV(amount);
Console.WriteLine("AddTV(amount)執行之後,amount=" + amount);

 那麼執行的結果呢?

圖片描述

amount的數量並沒有發生變化。

為什麼沒有變呢?

這是最入門的知識,通常的解釋是:

amount是int型別,int是值型別,所以當它作為引數時,傳遞給方法的是它的一個副本(複製品),因此方法中改變的是它的副本的值,amount本身並沒有改變。

ref 關鍵字,如下所示:

static void AddTV(ref int amount)
{
    amount++;
    Console.WriteLine("方法中,amount="+amount);
}

大家自己跑一下,看看結果有什麼不一樣。

這叫做引數的引用傳遞。

 

這是最基礎的知識,非常清晰。好的,接著,C#是物件導向的語言嘛,我們要引入一個物件。

public class House
{
    public int TVAmount { get; set; }
}

然後,我們把House物件作為引數傳遞,值傳遞,不帶ref的。如下所示:

static void AddTV(House house)
{
    house.TVAmount++;
    Console.WriteLine("方法中,house.TVAmount=" + house.TVAmount);
}
 
 
    House house = new House();
    AddTV(house);
    Console.WriteLine("AddTV(house)執行之後,house.TVAmount=" + house.TVAmount);

執行之後你會發現:

圖片描述

咦?house.TVAmount的值變了耶!

為什麼呢?

有的同學聽到的解釋是這樣的:

House是物件,是引用型別,引用型別作為引數傳遞到方法中,它的值會被方法改變。

 

值型別傳進去不變,引用型別傳進去要變,但值型別引用傳遞又要變……雖然有點繞,但死背下來也行。

講課這些天(五)怎麼才能把程式碼寫好?)

值型別的引用傳遞,和引用型別的值傳遞,效果都一樣,那他們有什麼區別呢?

 

Good question!

實際上,死背上面的,是會出問題的,我還是用程式碼展示一下:

static void AddTV(House house)
{
    house = new House();
    house.TVAmount++;
    Console.WriteLine("方法中,house.TVAmount=" + house.TVAmount);
}


這樣寫,眼尖的同學一眼就能看出差別:這一次方法體內多了一個:house = new House();

不要以為這是抽風啊,實際的開發程式碼中,各種各樣的原因,很多時候都確實會在方法體內重新new一個引數例項的。

那執行結果怎麼樣的呢?

圖片描述

怎麼樣?!引用型別也不好使了?


不像JavaScript到處都是bug和設計缺陷(是的,日常黑js一百年,),C#是一門嚴謹清晰的語言,不會有什麼“靈異”事件。現象和你的想法不一致,一定是你的想法出了問題。

所以,要真正地弄明白這裡面的道道,我們還是要回到原點:

 

首先的首先,看看這程式碼,你真的明白是什麼意思麼:

House house
    =
    new House();

我為什麼要寫成三行?

因為這其實是三個過程:

  • House house 這是宣告瞭一個變數

  • new House() 這是生成了一個物件

  • = 把 house 和 new House() 關聯起來

注意,注意我用的是“關聯”,很多人喜歡說“賦值”,甚至“等於”,這就容易造成我們理解上的誤區。

house和New House,是不同的資料儲存。事實上,在house裡面,有一個記錄了new Houuse()儲存位置的“引用”(reference,這個英文單詞有助於我們理解)。所以,當我們house.TVAmount的時候,是透過house找到new House(),然後得到new House()的資料進行操作。

不知道大家能不能明白這一點?

整個這一塊都是int i,int i 裡面就直接的儲存了10這個資料,沒有引用,int i裡直接存放數值10,所以叫做“值型別”。

 

好了,理解了上面的概念之後,我們回頭來看方法引數。

C#的說法非常的清晰,只看有沒有 ref 關鍵字:

  1. 不帶ref的,一定是“值傳遞”

  2. 帶ref的,一定是“引用傳遞”

和傳遞的是什麼型別的引數,半毛錢關係沒有。

關鍵是,你要知道:當引數為引用型別時,傳遞的不是物件(new House()),而是物件的引用(house)

所以,

  • 如果是值傳遞,傳遞的是 物件引用的 副本

  • 如果是引用傳遞,傳遞的是 物件引用 本身

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/2041/viewspace-2799960/,如需轉載,請註明出處,否則將追究法律責任。

相關文章