2013年10月29日 星期二

小山的 C# 教學-第26課-Get & Set 存取器

本課簡介

為了要防止 class 內部的變數遭到不正常操作
我們可以將變數設為 private 再提供 public method 存取

C# 特別為了上述狀況打造了 Get & Set 存取器
讓程式碼能夠更為簡潔整齊

教學影片

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



重點提示

1. Get & Set 存取器的語法如下: ......... // 宣告變數(通常是 public) { get { .... } // 希望變數讀取時執行的程式碼 set { .... } // 希望數值存入時執行的程式碼 }
2. 如果只使用 get 而去除 set 的話,該變數將會變為唯讀

3. 使用 Get & Set 存取器時,並不一定要有對應的 private 變數

4. Get & Set 存取器可以用來即時運算一些平常大家認為是變數的數值,像是 Money

練習

你現在是一位遊戲公司的設計師,這次受命完成玩家類別的部分程式碼
其中必須要完成以下兩項工作:

1. 撰寫計算玩家身上物品總值(TotalValue) 的程式碼

2. 撰寫讓外部物件存取飢餓度(HungerRate) 的程式碼

注意:飢餓度必須介於 0~100 之間,所以要想辦法防止外人存取時超出範圍

以下是玩家的部分程式碼,請完成 TODO 的部分: class Player { private int countGold; // 擁有的金子數目,每個金子值 50 private int countSilver; // 擁有的銀子數目,每個銀子值 25 private int countCopper; // 擁有的銅的數目,每個銅值 10 // TODO: 欠缺計算總值的程式碼 private int hungerRate; // 飢餓度,必須介於 0~100 之間 // TODO: 欠缺存取飢餓度(hungerRate) 的程式碼 public Player() { this.countGold = 0; this.countSilver = 0; this.countCopper = 0; this.hungerRate = 80; } public void pickAGold() { countGold++; } public void pickASilver() { countSilver++; } public void pickACopper() { countCopper++; } } 當你完成後,請建立一個 Windows Form 專案
並加入一個新的 Player class 檔案
將剛剛撰寫的程式碼替換掉 player.cs 中 class 的程式碼

另外在視窗放置一個簡單的按鈕
將下列的測試用程式碼貼上: private void button1_Click(object sender, EventArgs e) { Player player = new Player(); player.pickAGold(); player.HungerRate += 10; // 餓了,飢餓度上升 player.pickASilver(); player.HungerRate += 10; // 餓了,飢餓度上升 player.pickASilver(); player.HungerRate += 10; // 餓了,飢餓度上升 MessageBox.Show("飢餓度:" + player.HungerRate + ",身上物品總值:" + player.TotalValue); player.pickACopper(); player.HungerRate -= 60; // 吃了一個可以減少 60 飢餓度的東西 player.pickAGold(); player.HungerRate -= 60; // 吃了一個可以減少 60 飢餓度的東西 MessageBox.Show("飢餓度:" + player.HungerRate + ",身上物品總值:" + player.TotalValue); } 理論上當你按下按鈕執行後,應該要得到兩個對話框如下:



如果你的結果一模一樣,那就表示你成功囉!

相關資訊連結

微軟官方(MSDN) 對於 get 的介紹

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

微軟官方(MSDN) 對於 set 的介紹

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

17 則留言:

  1. 大哥 說實在的我沒有成功 有沒有正解阿!

    回覆刪除
    回覆
    1. 當然有正解囉~

      之後我可能會找一天整理所有問題的解答
      在這之前就請你多想想看囉

      刪除
  2. public int HungerRate
    {
    get { return hungerRate; }
    set {
    if (value >= 100)
    hungerRate = 100;
    else if (value <= 0)
    hungerRate = 0;
    else
    hungerRate = value;
    }
    }

    回覆刪除
  3. 執行成功!不過對於TotalValue的結果不太能理解耶...為什麼是100跟160呢?可以請小山老師講解一下嗎^^?

    回覆刪除
    回覆
    1. 因為在執行的程式碼中
      第一次顯示之前,玩家一共撿了 1 個金子跟 2 個銀子
      家裡來總共為 100 (50 + 25 * 2)

      到第二次顯示之前,玩家又撿了 1 個金子跟 1 個銅
      這個時候別忘記之前身上就已經有 100 了
      所以再增加 60 (50 + 10) 之後
      就變成 160 了

      請問這樣有回答道你的問題嗎?

      刪除
    2. 瞭解囉!謝謝小山老師的詳細解說~

      刪除
    3. 小山老師 我這邊的TotalValue 不知道為甚麼根您的結果不太一樣 我的是120跟170 不懂為甚麼 我在邊附上我打的程式碼
      Player player = new Player();

      player.pickAGold();
      player.HungerRate += 10; // 餓了,飢餓度上升

      player.pickASilver();
      player.HungerRate += 10; // 餓了,飢餓度上升


      player.pickASilver();
      player.HungerRate += 10; // 餓了,飢餓度上升

      MessageBox.Show("飢餓度:" + player.HungerRate + ",身上物品總值:" + player.TotalValue);

      player.pickACopper();
      player.HungerRate -= 60; // 吃了一個可以減少 60 飢餓度的東西

      player.pickAGold();
      player.HungerRate -= 60; // 吃了一個可以減少 60 飢餓度的東西

      MessageBox.Show("飢餓度:" + player.HungerRate + ",身上物品總值:" + player.TotalValue);

      internal class User// 使用者名稱 以及使用者密碼
      {
      private string Username;//名稱
      private string Password;//密碼
      private int hP;//血量
      private int count1, count5, count10; //硬幣


      public int Money // 統計自己有多少錢 只有get 代表指能讀取 不能存入
      {
      get
      {
      return count1+ count5*5+count10*10;
      }
      }

      public int HP
      {
      get { return hP; } // 在讀取HP時 會自動呼叫 //如果只留下get 讀取 那麼該變數 就會變成唯讀只能讀取 不能存
      set // 存入數值時會自動呼叫
      {
      if (value < 0) // 這邊的value就代表存入的值 例如:uesr.HP = 10 這邊的10就是value 10<0 不成立 所以 hp= value hp就等於10
      hP = 0;
      else
      hP=value;
      }
      }

      public User(string username, string password)//建構子 使用者的物件 建構子
      {
      this.Username = username;
      this.Password = password;
      this.hP = 100; //設定一開始的血量所有同類的物件 都是100
      count1 = 1; // 1塊硬幣有1個
      count5 = 5;//5塊硬幣有5個
      count10 = 10;//10塊硬幣有10個
      }

      public void hurt(int decreaseHP) // decrease 減少的意思 hurt 受傷的意思
      {
      if (hP >= decreaseHP)
      hP -= decreaseHP;
      else
      hP = 0;
      }
      public int getHP() // 讀取 血量
      {
      return hP;
      }
      public bool Comparepassword(string targetpassword) //Comparepassword 比較密碼 targetpassword 目標密碼
      {
      if (this.Password == targetpassword)
      {
      return true;
      }
      else
      {
      return false;
      }

      }
      public string getusername()//呼叫 使用 名稱
      {
      return Username;
      }

      }


      刪除
    4. 不好意思 打擾了 我找到答案了 我的public int TotalValue 這個屬性裡面的統計金額的 寫成兩個countCopper

      刪除
  4. 小山老師您好,想請問以下寫法是否妥適,在寫的途中發現只要在button按鈕事件中沒有先assign TotalValue值的話,set 是不是不會有作用,所以這題總資產要在 get裡面先寫好,又或者是在外面先寫好method之後在get裡面呼叫,這樣的想法是正確的嗎?

    private int totalvalue;
    public int TotalValue
    {
    get
    {
    totalvalue = 50 * this.countGold + 25 * this.countSliver + 10 * this.countCopper;
    return totalvalue;
    }
    }

    回覆刪除
    回覆
    1. 恩,這樣想法是對的
      這題就是要求你用 get 存取器來完成 TotalValue
      因此當你呼叫 TotalValue 時,他都會即時計算總金額為多少

      刪除
  5. 小山老師
    我想請教一下所謂的"自動屬性實作"
    程式碼如下
    class Student
    {
    public string StuID{ get; set; }
    public string StuName{ grt; Srt; }
    }

    這段程式碼是何意義呢??
    我搞不太懂它的用途@@
    請小山老師解惑
    12萬分感謝!!!

    回覆刪除
  6. 作者已經移除這則留言。

    回覆刪除
  7. 大家好,我在寫練習題那邊HungerRate那個method的時候一直寫不出來,到網路上查資料之後才突然想到解決答案
    我不直接顯示以免大家直接看到就不能自己寫了,但是如果真的沒有頭緒可以看一下!(我放下面一點以免你們不小心看到)








































































    可以在HungerRate的method的get&set那邊的set裡面先打(private的變數)hungerRate = value
    之後再用一個if與一個else if來限制答案不要超過100並且不要小於0!!

    回覆刪除
  8. 終於成功了!! 原本卡在value概念不清楚,出錯時才發現對value是錯的(把value當作加數....)

    回覆刪除
  9. public int TotalValue
    {
    get { return countCopper * 10 + countSilver * 25 + countGold * 50; }
    }
    public int HungerRate
    {
    get { return hungerRate; }
    set
    {
    if (value > 100)
    hungerRate = 100;
    else if (value <= 0)
    hungerRate = 0;
    else
    hungerRate = value;
    }
    }
    久違的交作業
    一開始不知道if else if else的用法
    在做HungerRate時一直在想怎樣設定飢餓度在0~100之間
    後來看了留言之後才恍然大悟

    回覆刪除
  10. private void button9_Click(object sender, EventArgs e)
    {
    Player player = new Player();

    player.pickAGold();
    player.HungerRate += 10; // 餓了,飢餓度上升

    player.pickASilver();
    player.HungerRate += 10; // 餓了,飢餓度上升


    player.pickASilver();
    player.HungerRate += 10; // 餓了,飢餓度上升

    MessageBox.Show("飢餓度:" + player.HungerRate + ",身上物品總值:" + player.TotalValue);

    player.pickACopper();
    player.HungerRate -= 60; // 吃了一個可以減少 60 飢餓度的東西

    player.pickAGold();
    player.HungerRate -= 60; // 吃了一個可以減少 60 飢餓度的東西

    MessageBox.Show("飢餓度:" + player.HungerRate + ",身上物品總值:" + player.TotalValue);
    }

    請問小山老師 為甚麼我出來的結果 根您的不太一樣 飢餓度對了 可是總值 第一次顯示是120 第二次顯示是170 到底哪裡有問題呢
    internal class Player
    {
    private int countGold; // 擁有的金子數目,每個金子值 50
    private int countSilver; // 擁有的銀子數目,每個銀子值 25
    private int countCopper; // 擁有的銅的數目,每個銅值 10
    private int hungerRate; // 飢餓度,必須介於 0~100 之間

    // TODO: 欠缺計算總值的程式碼
    public int HungerRate //存入或讀取 飢餓度的屬性 // TODO: 欠缺存取飢餓度(hungerRate) 的程式碼
    {
    get { return hungerRate; }
    set
    {
    if (value < 0)
    hungerRate = 0;
    else if (value>=100)
    hungerRate = 100;
    else
    hungerRate = value;
    }
    }
    public int TotalValue
    {
    get
    {
    return countGold * 50 + countSilver * 25 + countSilver * 10;
    }
    }





    public Player()
    {
    this.countGold = 0;
    this.countSilver = 0;
    this.countCopper = 0;
    this.hungerRate = 80;//飢餓度80
    }

    public void pickAGold()
    {
    countGold++;
    }

    public void pickASilver()
    {
    countSilver++;
    }

    public void pickACopper()
    {
    countCopper++;
    }

    }

    回覆刪除
    回覆
    1. 兄弟,你在這段return countGold * 50 + countSilver * 25 + countSilver * 10;
      寫了兩個銀塊,最後一個是 countCopper * 10; 才對哦

      刪除