屬性存取器:封裝的核心機制
屬性提供 get(讀取)與 set(寫入)存取器,實現封裝:
- 欄位設為
private,透過屬性控制存取邏輯
- 可單獨實作
get(唯讀)或 set(唯寫,罕見)
- 存取器可有不同存取修飾詞:
public string Name { get; private set; }
- 屬性不一定對應欄位(計算屬性、驗證、延遲載入等)
abstract 與 virtual/override 組合規則
| 組合 | 合法性 | 說明 |
abstract + virtual | ❌ 編譯錯誤 | abstract 隱含 virtual,不可重複標記 |
abstract + static | ❌ 編譯錯誤 | 靜態成員無法多型 |
abstract + override | ✅ 合法 | 抽象覆寫:強制衍生類別重新實作 |
virtual + override | ✅ 合法 | 一般覆寫:提供預設實作並允許再覆寫 |
sealed + override | ✅ 合法 | 密封覆寫:禁止後續覆寫 |
abstract override 實戰:抽象覆寫基底虛擬方法
using System;
class BaseClass {
public virtual void F() => Console.WriteLine("BaseClass.F");
}
// 方式 1:new + abstract(隱藏基底實作)
abstract class Derive1 : BaseClass {
public abstract new void F(); // 隱藏基底 F,衍生類別必須實作新 F
}
// 方式 2:abstract override(抽象覆寫,保留多型鏈)
abstract class Derive2 : BaseClass {
public abstract override void F(); // 保留虛擬槽位,強制再覆寫
}
class Concrete : Derive2 {
public override void F() => Console.WriteLine("Concrete.F");
}
class Program {
static void Main() {
BaseClass obj = new Concrete();
obj.F(); // Concrete.F (多型生效)
Console.ReadKey();
}
}
關鍵差異:new vs abstract override
| 特性 | abstract new | abstract override |
| 虛擬方法槽位 | 新增槽位(隱藏基底) | 重用基底槽位 |
| 多型行為 | 基底參考呼叫基底實作 | 基底參考呼叫衍生實作 |
| 適用場景 | 刻意中斷繼承鏈 | 強制重新設計演算法但保留契約 |
密封類別與虛擬方法
class Base { public virtual void F() => Console.WriteLine("Base.F"); }
sealed class Derived : Base {
// 基底虛擬方法隱式變為非虛擬(無法再被覆寫,因無衍生類別)
// 編譯錯誤:密封類別不能宣告新虛擬方法
// public virtual void G() { }
}
sealed class 繼承基底虛擬方法 → 隱式 sealed override(因無後代)
sealed class 不能宣告新的虛擬方法
最佳實踐總結
- 預設成員
non-virtual,需要多型才加 virtual
- 覆寫時預設
override,確定不再變動才加 sealed
- 介面優於抽象類別定義契約
- 抽象覆寫 (
abstract override) 用於 Template Method 強制子類別實作關鍵步驟
- 避免
new 隱藏虛擬方法(易造成多型錯誤),除非刻意設計