在類別內部,任何函式成員都能直接透過名稱存取同一類別的其他所有成員。
存取修飾子是成員宣告的選用前置詞,用來限制程式其他程式碼是否能夠存取該成員,寫在型別、方法名稱前方。
欄位
存取修飾子 型別 欄位名稱
方法
存取修飾子 傳回型別 方法名稱()
{
...方法主體
}
五種存取權限
private私用public公開protected保護internal內部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)
- 私用成員(F1、F2、DoCalc()):只有
C1類別內的程式碼能夠讀寫、呼叫,外部類別完全看不到; - 公開成員(F3、GetVal()):程式內任意其他類別、物件都能不受限制存取;
- 類別內規則:
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)

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