iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 22
0
Modern Web

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

Day22-C#-怎麼建立類別Class及其建構函式Constructor(建構子)、屬性 (Properties)、欄位 (Field)、方法 (Method)

在C#中以Class{...}來定義一個類別,類別定義是一個全域宣告的概念,要放在namespace{...}內,但不能放在方法中。類別內可以有建構函式 (Constructor)、屬性 (Properties)、欄位 (Field)、方法 (Method)

Class架構

Class架構如下(以console模式為例):

https://ithelp.ithome.com.tw/upload/images/20190923/20120055j1GP8TyjVG.png
(圖片繪製參考:[C#][Visual Studio] 類別與物件 (class and object))

存取修飾詞

類別、類別資料成員們(方法、屬性、欄位、建構函式)可以使用存取修飾詞宣告存取範圍,控制可以從哪裡使用它們,預設值為private,其他存取修飾詞如下:

存取修飾詞 作用 存取範圍
public 公開 無限制
private(預設) 私有 只有本身類別可以存取
protected 保護 父類別或繼承自父類別的子類別(衍生類別)
internal 內部 限於目前專案(組件)
protected internal 限於目前專案或是繼承自父類別
private protected 存取限於目前專案內包含類別或衍生自包含類別的類型。自C#7.2起可用。

注意:namespace是不能使用存取修飾詞的

完成類別設定之後,必須實體化為物件,透過new這個關鍵字來初始化

SayHi yo =new SayHi();

建構函式 (Constructor)(建構子)

你如果有使用聰明的IDE及套件,可能會看過這個畫面

https://ithelp.ithome.com.tw/upload/images/20190923/201200557XuDAlEsp7.png

這代表DateTime這個類別在宣告時,你有很多種方式可以給定參數並初始化那個物件

也就是建構子可以設定是否要接受參數來初始化一個新的物件,與宣告方法很相似,有幾點需要注意:

  1. 建構子的函式名稱需與類別相同
  2. 存取修飾詞為public
  3. 不能有回傳值
  4. 不能使用void
  5. 不會被繼承
  6. 類別內可以沒有建構函式,代表初始化時不用帶入參數,也稱為預設建構函式Default Constructor
  7. 依據需求,類別內可以有多個建構函式(多載overloading)
  8. 除非類別是靜態,否則沒有建構函式的類別會從C#編譯器取得一個公開無參數建構函式,以啟用類別具現化

範例(取自MSDN-使用建構函式):

public class Employee//建立一個Employee的類別
{
    public int Salary;//設定一個叫Salary的欄位

    public Employee(int annualSalary)//第一個建構函式,帶入一個int參數,初始化時會將參數賦值給Salary
    {
        Salary = annualSalary;
    }

    public Employee(int weeklySalary, int numberOfWeeks)//第二個建構函式,帶入2個int參數,初始化時會將參數第一個參數與第二個參數相乘後,賦值給Salary
    {
        Salary = weeklySalary * numberOfWeeks;
    }
}

於是接下來當要new 一個Employee類別的物件時,可以使用下列任一陳述式建立

Employee staff = new Employee(30000);
Employee manager = new Employee(500, 52);

屬性 (Properties)與欄位 (Field)

這兩個使用上很像一般變數,呼叫也都是用"."

物件.欄位
物件.屬性

但有時候我們既希望他可以像變數一樣被使用,又想要偷偷的對這個變數做一些處理,不讓使用的人知道,這時候就可以採用支援存放(baking store)的作法,配合存取子(Accessor)的get/set做存取以及額外的處理。

舉例來說,我們要設定一個快樂體重計的屬性是重量weight,小於就顯示0,大於也只會顯示60。
若只是單純宣告public會被發現,也能夠隨意設定超出範圍的值,這時可以如下方這樣寫

class Program
{
    static void Main(string[] args)
    {
        scales scales =new scales();
            scales.weight = 200;
            Console.WriteLine($"你的體重是{scales.weight}");
            Console.ReadKey();
     }
     public class scales//定義scales類別
     {
         private int newWeight;//newWeight為private,只能在scales內使用
         public int weight
         {
             get//get存取子可以回傳屬性值
             {
                 return newWeight;//使用return回傳屬性值
             }
             set//set存取子可以設定屬性值,value是外部傳來的數字
             {
                 if (value < 0)//如果小於0就設為0
                 {
                     value = 0;
                 }
                 if (value > 60)//大於60就顯示60
                 {
                     value = 60;
                 }
                 newWeight = value;//把調整後的value值賦值給newWeight
              }
           }
      }
}

輸出結果:
https://ithelp.ithome.com.tw/upload/images/20190923/20120055lOkvtVIKAa.png

當使用scales.weight=200設定屬性值時,程式會執行set{...}區段,value的值就是200,value經過處理後把值賦值給內部變數newWeight,接下來要讀取scales.weight的值時,會執行get{...}區段,傳回newWeight

怎麼設定唯讀/唯寫屬性?

唯讀: 不放set{...}即可
唯寫: 不放get{...}即可

自動屬性

在類別內使用get和set存取子設定屬性最大優點是可以隱藏我們真的要做的事情(資料封裝),但如果我們只是要達到資料封裝但實際上沒有要做任何調整,寫法會像下方程式碼一樣:

public class scales
{
    private int newWeight;
    public int weight
    {
        get{return newWeight;}
        set{newWeight = value;}
    }
}

這樣有點太繁瑣了,Visual C#2008版本開始提供自動屬性實作,存放屬性的私有變數會由編譯器自動建立,所以可以改寫成下方這樣,精簡多了!

public class scales
{
    public int weight{get;set;}
}

方法 (Method)

方法是包含一系列陳述式的程式碼區塊,例如Main()就是一個方法。建立方法的方式與建構子很類似,如下方

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

輸出結果:
https://ithelp.ithome.com.tw/upload/images/20190923/20120055HWNd0PWYMG.png
預設為傳值呼叫Call By Value,amount的值是不會改變的!

如果希望amount的值跟著改變,需要使用參考呼叫Call By Reference,加上"ref"在方法宣告及使用上,如下方

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

輸出結果:
https://ithelp.ithome.com.tw/upload/images/20190923/20120055E4TTQCeian.png
這樣amount的值就會被改變了!

呼叫方式也是用"."的運算子,與屬性最大差別為方法後方一定跟著"( )"。
同時也 支援多載 ,同一個方法名稱可以依據參數不同執行不同功能的方法,如下方

static void Main(string[] args)
{ 
    int newAmount = addMoney(1000);//呼叫addMoney的方法並賦值給newAmount,由於是傳入int參數,會執行第一個方法
    Console.WriteLine(newAmount);
    string name = addMoney("Cynthia~");//呼叫addMoney的方法並賦值給name,由於是傳入string參數,所以會執行第二個方法
    Console.WriteLine(name);
    Console.ReadKey();
}
 
private static int addMoney(int amount)//第一個方法
{
    amount = amount * 2;
    return amount;
}
private static string addMoney(string amount)//第二個方法
{
    amount = amount+"hi";
    return amount;
}

到這裡有沒有發現之前我們寫的小工具例如檢查身分證字號的程式,可以把它包成一個方法,這樣就可以呼叫該方法執行打包後的程式碼,不用落落長的擠在主程式裡,可以變得更好維護喔~


參考資料

[C#][Visual Studio] 類別與物件 (class and object)
MSDN-存取範圍層級
MSDN-存取修飾詞
MSDN-使用建構函式
從零開始學Visual C# 2017程式設計
Visual C# 2017程式設計經典


上一篇
Day21-C#物件與類別
下一篇
Day23-C#-傳說中的static!!!靜態類別和靜態類別成員
系列文
C#與ASP.Net入門-我要成為工程師!!31

1 則留言

1
小朱
iT邦新手 4 級 ‧ 2019-09-24 18:32:50
  1. 參數的 by value, by reference 就足以講一整篇了。
    只有實值型態 (value type) 才會有這種差異,若參數是參考型態 (reference type) 就只有 by reference 一種傳法而已。

  2. 類別、屬性、方法等的命名要開始學習了,建議可參考網路上有些高手或前輩釋出的命名規範來做,像是類別要用大寫字母開頭、屬性和方法也是用大寫字母 (Java則是小寫字母) 開頭之類的。

1.立馬研究了這兩者寫成文章XD
2.好的orz...感謝大大提醒

我要留言

立即登入留言