相信有仔細看過前一篇文章後
對於C#中Value Type 與Ref Type有了一些初步的了解(才怪)
今天直接 Passing By Value 與 Passing By Reference來探討Value Type 與Ref Type的差別
話不多說舉個例子
1.參考型別(Reference Type)
假設某個學校出了一個模範生小明,老師希望以後所有的學生都像小明一樣聰明
所以把小明克隆了一個新的取名叫做小華
看以下程式碼
public static void Main()
{
var student1 = new Stutent();
student1.Name = "阿明";
var student2 = student1;
student2.Name = "小華";
Console.WriteLine(student1.Name);
}
class Stutent
{
public string Name{get;set;}
}
猜猜Output出什麼呢答案是小華
什麼?
為什麼?
靠北不是把令了一個新的變數student2來裝student1了嘛
那為什麼把新生出來的student2的名字取為小華
導致原本的小明也變成小華了呢
老師感到疑惑,小明到底跑哪去了呢,聰明的老師立刻打開電腦
Google了Msdn才發現 阿~! 小華原來就是小明 還裝?!
因為 Class Student是一個參考型別
參考型別的變數承載的是記憶體的位置
將一個新的座位,指派給小明,
並把新座位的主人改名為小華,
然後在請原本小明座位上的人大聲喊出自己的名字
小明 當然就會說 "我是小華" 囉
仔細看看這段程式碼
var student1 = new Stutent();
再把它中文翻譯
我宣告了一個變數student1 並指派為一個新的學生 口語邏輯上是這樣講
但在參考型別的情況下實際上背後做了什麼事呢?
其實這邊做了兩件事情
- 左式宣告變數時 會在stack記憶體區域中增加一個student1變數的值,而student1紀錄的是這個物件的位置
- 右式指派變數時 則會在student1所指定Heap記憶區塊中產生真正的Object內容並將這個Object所在的Heap位置傳給變數student1作為他的參考值
所以總歸結論(附上專有名詞以供Google)
- 使用class關鍵字宣告的型別為參考型別(reference type)。
- 參考型別的變數(variables)的值(value)儲存的是實體(instance)的位址而不是實體本身。
- 參考型別的參數傳遞的行為還是傳遞值,但變數的值裝載是實體的址。
2.實質型別(Value Type)
相對於參考型別的變數值儲存的是址,實質型別的變數的值儲存的是確確實實的個體
public static void Main()
{
var student1 = new Student();
student1.Name = "阿明";
var student2 = student1;
student2.Name = "小華";
//output "阿明"
Console.WriteLine(student1.Name);
//output "小華"
Console.WriteLine(student2.Name);
Console.ReadKey();
}
public struct Student
{
public string Name { get; set; }
}
現在可以看到student1與student2都是獨立的個體了,
因為實質型別的變數傳遞是傳值(passing by value)
var student2 = student1;
這時候上面這一句宣告背後做的事情實際上的行為是在Stack記憶區中建立student2的變數並student1的值複製後傳進此變數。
實質型別除了使用Struct關鍵字外宣告,
C#中已經內建宣告了15種實質型別 請參照 實質型別表
所以在此做一個簡單的實質型別結論:
- 實質型別(value type)的類別宣告(declare)使用Struct關鍵字(keyword)。
- 變數直接儲存目標的值。
- 實質型別的變數的傳遞,是將本身複製一份並傳遞進變數。
小小心得
若有謬誤
歡迎底下留言指正討論
參考 https://www.microsoftpressstore.com/articles/article.aspx?p=2454676
留言
張貼留言