在 C# 面向對象設計中,interface(介面)、abstract(抽象類/方法)與 virtual(虛擬方法)是實現多態與擴展性的三大基石。雖然它們都涉及「契約」與「重寫」,但語義、約束與適用場景截然不同。本文通過代碼實例,系統梳理三者的異同點與最佳實踐。
public、abstract、virtual 等修飾符,默認即為 public。class MyClass : IInterface1, IInterface2。public interface IPerson
{
void GetName(); // 正確:無參方法
void GetAge(string id); // 正確:帶參方法
// IPerson() { } // 編譯錯誤:不可有構造函數
// string Name; // 編譯錯誤:不可有字段
// public void Show(); // 編譯錯誤:不可加修飾符
}
public class Chinese : IPerson
{
public Chinese() { } // 自身構造函數合法
public void GetName()
{
Console.WriteLine("Chinese.GetName");
}
public void GetAge(string id)
{
Console.WriteLine($"Chinese.GetAge: {id}");
}
}
abstract 方法的類必須聲明為 abstract class。override 實現。public abstract class Book
{
public Book() { Console.WriteLine("Book ctor"); }
public abstract void GetPrice(); // 必須由子類實現
public virtual void GetName() // 可選覆蓋
{
Console.WriteLine("Book.GetName");
}
public void GetDate() // 普通方法,子類用 new 隱藏
{
Console.WriteLine("Book.GetDate");
}
}
public class JavaBook : Book
{
public override void GetPrice() // 必須實現
{
Console.WriteLine("JavaBook.GetPrice: $39.9");
}
public override void GetName() // 選擇覆蓋
{
Console.WriteLine("JavaBook.GetName: Effective Java");
}
// 不覆蓋 GetDate(),調用基類實現
}
Book book = new JavaBook();
book.GetPrice(); // 輸出: JavaBook.GetPrice: $39.9 (動態綁定)
book.GetName(); // 輸出: JavaBook.GetName: Effective Java
book.GetDate(); // 輸出: Book.GetDate (靜態綁定)
virtual 方法提供完整默認實現,派生類可選擇性用 override 覆蓋。new 隱藏(非多態)。public abstract class Base
{
public virtual void VirtualMethod() { Console.WriteLine("Base.Virtual"); }
public void NormalMethod() { Console.WriteLine("Base.Normal"); }
}
public class Derived : Base
{
public override void VirtualMethod() { Console.WriteLine("Derived.Virtual"); } // 多態
public new void NormalMethod() { Console.WriteLine("Derived.Normal"); } // 隱藏
}
Base obj = new Derived();
obj.VirtualMethod(); // Derived.Virtual (動態分派)
obj.NormalMethod(); // Base.Normal (靜態分派)
| 特性 | Interface | Abstract Method | Virtual Method |
|---|---|---|---|
| 是否有實現 | 無 | 無 | 有(默認實現) |
| 派生類義務 | 必須實現所有成員 | 必須 override 實現 | 可選 override |
| 多態支持 | 是 | 是 | 是 |
| 可包含字段/構造函數 | 否 | 是(在 abstract class 中) | 是(在普通類中) |
| 多重實現/繼承 | 多介面實現 | 單繼承 | 單繼承 |
| 典型場景 | 定義能力契約、插件架構 | 模板方法模式、框架骨架 | 策略默認實現、擴展點 |
sealed)或關鍵路徑避免虛擬調用開銷。override 方法加 XML 註釋說明前置/後置條件,防止違反里氏替換原則(LSP)。理解 Interface、Abstract 與 Virtual 的本質區別,是寫出可維護、可擴展 C# 代碼的關鍵。選對工具,事半功倍。