2013年3月24日 星期日

小山的 C# 教學-第16課-Value 與 Reference Type

本課簡介

本課主要在介紹 C# 之中兩大類型的型別(Type)
分別是 Value Type 與 Reference Type
針對這兩種類型在記憶體儲存的方式做稍微深入地介紹

教學影片

注意:影片有高畫質 720P 的選項,可以看得更清楚喔!



重點提示

1. C# 型別(Type) 依照存取方式不同一共分為三種:Value Type、Reference Type 與 Pointer Type

2. C# 變數裡的資料都是存放在記憶體(Memory)內的

3.「int (整數)」就是一種 Value Type。它會先在記憶體中尋找一個空間,標記為變數名稱,然後將我們指定的數值存入

4. 上一課建立的 Student Class 則是一種 Reference Type。宣告 Reference Type 的變數時,也會先在記憶體中尋找一個空間,標記為變數名稱,然後裡面則「存放物件的記憶體位置」。

5. 物件必須要透過「new Class名稱()」的方式建立,沒有指向任何物件的 reference(參考) 變數,則存放著「null」。

6. 物件都是存放在一個稱為「Heap(堆疊)」的特殊記憶體區塊

補充

Pointer 指標

有學過 C/C++ 程式語言的人相信都不陌生,而對部分的人來說,指標則是他們學習 C/C++ 的噩夢之一。指標是一種「專門存放記憶體位置」的變數。因為記憶體操作是一種非常危險的行為,而導致程式時常會不明地中斷。當然,如果對指標的行為有高度地了解,並且對程式使用記憶體的行為非常了解的話,就不會遇到這些錯誤。

一般來說,純物件導向的程式語言為了要隱藏背後複雜的操作行為,是不會給予使用者使用指標。例如 JAVA 的型別就只有兩種,Primitive Type 與 Class Type。但是 C# 則保留了指標這個型別,個人猜想可能是為了要延續 C/C++ 指標所扮演的重要性才留下來的。

練習

如果我們執行了下面的程式碼,最後對話框中會印出甚麼呢?(Student 為第 14、15 課編寫的 Student class)
Student s1 = new Student(); s1.Name = "小山"; s1.Grade = 3; Student s2 = s1; s2.Name = "小羊"; s2.Grade = 2; Student s3 = s1; s3.Name = "高光"; s3.Grade = 5; Student s4 = s2; s4.Name = "元整"; s4.Grade = 1; MessageBox.Show(s4.Say());
執行看看驗證自己的答案吧~

相關資訊連結

內建型別資料表 (除了 object 與 string 外,表中的型別都是 value type)

http://msdn.microsoft.com/zh-tw/library/ya5y69ds.aspx

實質型別的所有類型

http://msdn.microsoft.com/zh-tw/library/s1ax56ch.aspx

30 則留言:

  1. 作者已經移除這則留言。

    回覆刪除
  2. 我分別秀4個值S1-S4...答案都是最後的值(元整,1)....這邊很怪呢!是否能請小山老師解釋說一下~Q.Q?
    只要是 Reference Type 的質~它都只會抓最後被修改的數?S1被S2和S3取代~S2又被S4取代~
    所以全部的數都看最後取代的S4這樣說對嗎?那這個功能是拿來做什麼的呢?

    回覆刪除
    回覆
    1. 結果是正確的,先跟你確認這點

      只要是 Reference Type 的變數,都只會存著物件的「記憶體位置」
      在這個練習的例子之中
      可以想成最初使用 new Student() 建立的物件是一棟房子 H
      然後我使用 s1 去紀錄房子的地址
      我去修改 s1.name, s1.grade 都是修改到 H 裡面的東西
      接著 s2 = s1; 這行是把 s1 裡面存著的 H 的位置傳給 s2
      也就是說,s2 也是紀錄 H 的位置
      所以修改 s2.name, s2.grade 也是修改 H 的資料

      你慢慢看下來會發現其實最後
      s1, s2, s3, s4 都是記錄 H 的位置
      而且我們透過 s1, s2, s3, s4 修改資料時
      都是修改到 H 的資料
      所以 H 最後的資料當然就是最後 s4 那段程式碼執行完的結果囉!

      這時你如果在各自 s1.say()... 去看看資料的話
      也都是在看「同一個物件」的資料
      所以結果都會相同

      刪除
  3. 作者已經移除這則留言。

    回覆刪除
  4. 本來一直對這部分很有疑惑,感謝小山的教學!

    回覆刪除
  5. 小山老師想請問一下object 與 string 這兩個行別不算是 value type的話那他們算是哪種type呢?

    回覆刪除
    回覆
    1. 基本上,一般來說只要不是 value type
      通常都是 reference type
      pointer type 只有在極少狀況下才使用

      刪除
    2. object 與 string 都是 reference type

      刪除
    3. 作者已經移除這則留言。

      刪除
  6. 謝謝小山老師!!這邊變成我的練功房了~XD

    回覆刪除
  7. 講解的很詳細唷~~
    while(true)
    Good !!!
    終於把 class 和 new 搞懂了 ~~
    heap == 堆積
    stack == 堆疊
    感覺 reference 運作的模式 跟 pointer 一模一樣
    不知道 他們 差在哪裡 ~~~??? >< !!!

    回覆刪除
    回覆
    1. C# 通常不會使用到 pointer
      主要是 C++ 上面在用
      兩者概念上很像
      都是記錄某個記憶體位置
      只是使用方式上跟底層實作不太相同而已
      不過其實沒有在寫 C++ 的話就不太需要瞭解

      刪除
  8. 小山老師您好

    可否向您請教String也是Reference Type,為何下列程式碼不會像class一樣發生Ref的結果呢?
    String A = "";
    String B = A;
    B = "Ref";
    MessageBox.Show(A);

    回覆刪除
    回覆
    1. 請問你期望產生甚麼樣的結果呢?

      刪除
    2. MessageBox.Show(A); 是空的值吧!!

      刪除
  9. 小山老師您好

    可否向您請教String也是Reference Type,為何下列程式碼不會像class一樣發生Ref的結果呢?
    String A = "";
    String B = A;
    B = "Ref";
    MessageBox.Show(A);

    回覆刪除
    回覆
    1. 你好:

      因為這段程式碼的效果跟課程中不同。
      課程中是讓 s2 指向 s1 所指向的物件,然後透過這個位置去修改物件的內容。

      可是在你提供的程式碼中,你並沒有修改 A 這個物件,反而只是更改 B 指向的物件而已。
      在第二行中,你把 B 指向 A 物件。第三行則將 B 改成指向 "Ref" 這個物件。
      因此並沒有修改到 A 本身的內容。

      刪除
    2. 小山老師您好,

      這裡沒有修改到 A 這個物件,是因為字串跟一般的參考型別運作原理有點不同嗎?

      一般參考型別
      Student s =new Student();
      透過 new 這個指令到heap中建立一個物件並把記憶體位置回傳給(ref);

      字串
      String A = "";
      沒有new這個指令,所以不會直接到heap中建立一個物件,而是先到heap中尋找有沒有值相同的物件,如果沒有才建立一個新的物件並把記憶體位置回傳給A (ref);
      String B = A;因為B和A的值相同所以指向同一個物件;
      B = "Ref";因為Ref這個值是新的所以到heap中建立一個物件並把記憶體位置回傳給B (ref);

      也就是說如果要讓A和B指向同一個物件並修改物件的值就要寫成,
      String A = "";
      String B = A="Ref";

      研究了很久才看懂,覺得好像是這樣嗎?
      如果老師有空,希望可以再更新~~
      謝謝老師!!!

      刪除
  10. 小山老師,請問影片中,3:32之處,b=20是否應該為a=20呢@@?

    回覆刪除
  11. 老師請問參考型別主要是參考的是class的實作
    並不會一直堆疊很多資料占用記憶體對嗎??
    這跟override有何不同呢??

    回覆刪除
    回覆
    1. override 跟 reference 是完全不同的概念哦~
      建議可以先看看 override 的課程

      刪除
  12. 受益良多! 感謝小山老師

    回覆刪除
  13. 請問我想建議一個S5內容複製S1, 但是修改s5.name時,s1.name不會改變, 請問我要怎麼寫

    回覆刪除
  14. Student s1 = new Student();
    s1.Name = "小山";
    s1.Grade = 3;

    Student s2 = new Student();

    s2.Name = s1.Name;
    s2.Grade = s1.Grade;
    MessageBox.Show(s1.Say());
    MessageBox.Show(s2.Say());
    s2.Name = "小羊";
    s2.Grade = 2;
    MessageBox.Show(s1.Say());
    MessageBox.Show(s2.Say());

    回覆刪除
    回覆
    1. 我叫小山 ,我是 3 年級的學生
      我叫小山 ,我是 3 年級的學生
      我叫小山 ,我是 3 年級的學生
      我叫小羊 ,我是 2 年級的學生

      刪除
  15. 請問一下,
    如果把這裏的所有教學都學完了,
    距離把C#的所有功能精通差多少百份比左右?? (大約就可以了)
    * 本人的目標是在UNITY用C#寫遊戲的

    回覆刪除