六大存取層級完整對照表
| 修飾詞 | 可存取範圍 | 適用成員 | 典型用途 |
| public | 任何組件、任何類別 | 所有 | 公開 API、介面實作 |
| protected | 宣告類別 + 衍生類別 (跨組件) | 所有 | 基類別提供給衍生類別的擴充點 |
| internal | 同一組件內所有類別 | 所有 | 組件內部實作細節、單元測試友善 |
| protected internal | 同一組件 或 衍生類別 (跨組件) | 所有 | 組件內可用,跨組件僅衍生類別可用 |
| private | 僅宣告類別內部 | 所有 | 封裝實作細節、不變條件維護 |
| private protected | 同一組件內的衍生類別 | C# 7.2+,所有 | 組件內衍生類別專用,跨組件完全封鎖 |
預設存取層級
- 類別/結構體/介面/列舉/委派:
internal (頂層) / private (巢狀)。
- 類別成員 (欄位/方法/屬性/事件/索引子/運算子/建構子):
private。
- 介面/列舉成員:
public (不可變更)。
實戰範例:Vehicle/Train/Car 存取控制
class Vehicle {
public int Wheels; // 任何人可存取
protected float Weight; // Vehicle + 衍生類別可存取
internal string Vin; // 同組件可存取
protected internal int Age; // 同組件 或 衍生類別可存取
private Engine _engine; // 僅 Vehicle 可存取
private protected int Secret; // 同組件衍生類別可存取
public void Start() {
Wheels = 4; // OK
Weight = 100; // OK
_engine = new Engine(); // OK
}
}
class Train {
public int Carriages;
private int Passengers;
private float Weight; // 隱藏 Vehicle.Weight (不同成員)
public void Test(Vehicle v) {
v.Wheels = 4; // OK: public
// v.Weight = 6; // CS0122: protected 外部類別不可存取
v.Vin = "ABC"; // OK: internal 同組件
// v._engine = ... // CS0122: private 不可存取
Weight = 6; // OK: 自身 private
}
}
class Car : Vehicle {
public void Test(Vehicle v) {
v.Wheels = 4; // OK: public
v.Weight = 6; // OK: protected 衍生類別可存取基類別 protected
v.Vin = "XYZ"; // OK: internal 同組件
// v.Secret = 1; // CS0122: private protected 跨組件衍生類別不可存取
}
}
存取層級決策流程圖
- 需公開給所有消費者? →
public
- 需提供給衍生類別擴充 (跨組件)? →
protected
- 需組件內共享實作細節? →
internal
- 需組件內共享 + 跨組件衍生類別可用? →
protected internal
- 需完全封裝,僅本類別使用? →
private
- 需組件內衍生類別可用,跨組件完全封鎖? →
private protected (C# 7.2+)
常見設計錯誤
| 錯誤 | 後果 | 修正 |
欄位直接 public | 破壞封裝、無法驗證、序列化/繫結問題 | 改用 private 欄位 + public 屬性 |
過度使用 protected 欄位 | 衍生類別耦合基類別實作細節 | 改用 protected 屬性/方法 |
跨組件專案缺少 internal 可見性 | 單元測試專案無法存取被測類別內部 | 加上 [InternalsVisibleTo("TestAssembly")] |
混淆 protected internal (OR) 與 private protected (AND) | 存取範圍不符預期 | 記住:internal=組件、protected=衍生、OR/AND 邏輯 |
屬性/方法/事件/索引子/運算子/建構子 同樣適用
所有成員類型共用相同存取修飾詞規則,無特例。