存取修飾子

在類別內部,任何函式成員都能直接透過名稱存取同一類別的其他所有成員。

存取修飾子是成員宣告的選用前置詞,用來限制程式其他程式碼是否能夠存取該成員,寫在型別、方法名稱前方。

欄位

存取修飾子 型別 欄位名稱

方法

存取修飾子 傳回型別 方法名稱()
{
    ...方法主體
}

五種存取權限

  1. private 私用
  2. public 公開
  3. protected 保護
  4. internal 內部
  5. protected internal 保護內部

讀者目前先認識 private 與 public 即可,其餘權限留待後續課程說明。

無論使用何種修飾子,在類別內部都可以互相存取成員

參考下面範例

class Robot
{
    public string name;

    int age;

    public void SayHello()
    {
        Console.WriteLine($"Hello everyone my name is {name},I come from Foxdevelop.com");
        Console.WriteLine($"I am {age} years old");
    }

    void AgeUpdate()
    {
        age =  age+1;
    }

    void SayHi()
    {
        SayHello();
    }
}Code language: C# (cs)

從上面範例可以觀察到:不論是公開方法 SayHello、私用方法 AgeUpdate 與 SayHi,或是私用欄位 age、公開欄位 name,只要程式碼位於類別內,成員之間都能夠互相存取。

有一點要留意:不要撰寫互相呼叫的程式碼,會造成無限迴圈。舉例如下

class Robot
{
    public string name;

    int age;

    public void SayHello()
    {
        Console.WriteLine($"Hello everyone my name is {name},I come from Foxdevelop.com");
        Console.WriteLine($"I am {age} years old");
        SayHi();
    }

    void AgeUpdate()
    {
        age =  age+1;
    }

    void SayHi()
    {
        SayHello();
    }
}Code language: C# (cs)

此處 SayHi 會呼叫 SayHello,而 SayHello 又會呼叫 SayHi,互相呼叫會形成無限遞迴。

最後會造成程式崩潰

系統會提示記憶體溢位

另外,欄位初始化時不能直接呼叫一般方法,除非該方法為靜態方法。原因是一般成員方法必須透過物件實體才能呼叫。

class Robot
{
    public string name;

    int age = GetInt();

    static int GetInt()
    {
        return 1;
    }

    public void SayHello()
    {
        Console.WriteLine($"Hello everyone my name is {name},I come from Foxdevelop.com");
        Console.WriteLine($"I am {age} years old");
    }

    void AgeUpdate()
    {
        age =  age+1;
    }

    void SayHi()
    {
        SayHello();
    }
}Code language: C# (cs)

像上圖一樣將方法宣告為靜態即可使用。但要注意,透過這種方式設定 age 時,如果 GetInt 傳回的值不固定

class Program
{
    static void Main(string[] args)
    {
        Robot robot1 = new Robot();
        for (int i = 0; i < 100; i++)
        {
            robot1.WriteAge();
            System.Threading.Thread.Sleep(1000);
        }
    }
}

class Robot
{
    public string name;

    int age = GetInt();

    static int GetInt()
    {
        return DateTime.Now.Second;
    }

    public void WriteAge()
    {
        Console.WriteLine($"I am {age} years old");
    }
}Code language: C# (cs)

以上程式碼範例中,GetInt 會傳回當下時間的秒數。Main 內透過 for 迴圈執行 100 次輸出年齡的函式,每次輸出後暫停一秒再繼續執行。我們會發現

輸出的秒數永遠是初始化當下取得的數值。假設初始化 age 時 GetInt 取得秒數 45,之後 age 就固定為 45,不論後續執行多少次輸出都不會變動。這也對應上一節提到的規則:欄位初始值必須在建構階段確定。

接下來回到存取修飾子的主題

簡單總結:不論使用何種存取修飾子,在類別內部都可以存取所有成員。

private 私用存取

私用成員只能在宣告該成員的類別內部存取,其他任何類別都無法讀取、修改。

類別成員預設的存取層級就是 private,不寫修飾子等同於明確標註 private,兩種寫法語義完全相同

int MyInt1;              // 隱式私用(預設)
private int MyInt2;      // 顯式私用Code language: C# (cs)

public 公開存取

實體的公開成員允許程式中所有其他物件存取,必須手動加上 public 修飾子宣告

public int MyInt;        // 標註 public 存取修飾子Code language: C# (cs)

成員可見性規則

我們常使用類別圖來描述類別結構

整個類別以方框表示,成員則是類別內的小區塊;

private 成員:完整收納在類別方框內,外部無法看見;

public 成員:元件一部分延伸至類別方框外,代表全域可存取。

class Program
{
    int Member1;         // 隱式私用
    private int Member2; // 顯式私用
    public int Member3;  // 公開
}Code language: C# (cs)

本章範例

class C1
{
    int F1;                // 隱式私用欄位
    private int F2;        // 顯式私用欄位
    public int F3;         // 公開欄位

    void DoCalc()          // 隱式私用方法
    {
        ...
    }

    public int GetVal()    // 公開方法
    {
        ...
    }
}Code language: C# (cs)
  1. 私用成員(F1、F2、DoCalc()):只有 C1 類別內的程式碼能夠讀寫、呼叫,外部類別完全看不到;
  2. 公開成員(F3、GetVal()):程式內任意其他類別、物件都能不受限制存取;
  3. 類別內規則C1 自身所有方法,不論公私,都能夠存取同一類別所有欄位與方法。

可執行範例


class Program
{
    static void Main(string[] args)
    {
        Worker worker = new Worker();
        Console.WriteLine(worker.GetHours()); // 合法,可在類別外存取公開成員 GetHours
        Console.WriteLine(worker.ReadSavings());//錯誤,無法在類別外存取私用成員 ReadSavings,就算使用實體名 worker. 也不行

        Console.WriteLine(worker.hours); // 合法,可在類別外存取公開欄位 hours
        Console.WriteLine(worker.savings); //錯誤,無法在類別外存取私用欄位 savings
        Console.WriteLine(worker.age); //錯誤,無法在類別外存取私用欄位 age
    }
}

class Worker
{
    int age;                // 隱式私用欄位
    private double savings;        // 顯式私用欄位
    public int hours;         // 公開欄位

    void ReadSavings()          // 隱式私用方法
    {
        Console.WriteLine(savings);
    }

    public int GetHours()    // 公開方法
    {
        return hours;
    }
}Code language: C# (cs)

現在各位應該已經對存取修飾子有基礎認識

存取修飾子

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *