繼承是物件導向的核心,但當基類庫更新、新增了與衍生類別同名的方法時,會發生什麼情況?C# 提供了 new 修飾詞來明確表達「遮蔽」意圖,避免編譯器警告 CS0114。
假設你引用第三方庫的 BaseClass,並衍生出 DerivedClass 實作 TestMethod()。若未來基類也加入同名方法,若無 new 修飾詞,編譯器會警告:
'DerivedClass.TestMethod()' hides inherited member 'BaseClass.TestMethod()'. To make the current method override that implementation, add the override keyword. Otherwise add the new keyword.
class BaseClass
{
public void TestMethod()
{
Console.WriteLine("BaseClass::TestMethod");
}
}
class DerivedClass : BaseClass
{
new public void TestMethod()
{
Console.WriteLine("DerivedClass::TestMethod");
}
}
加上 new 後,編譯器知道這是刻意遮蔽。但注意:若透過基類參考呼叫 ((BaseClass)derived).TestMethod(),仍會執行基類實作——這與 override 多型行為不同。
屬性提供 get/set 存取子,能隱藏內部儲存細節、驗證資料、實作唯讀或唯寫邏輯。
public class House
{
private int m_nSqFeet; // 後端欄位
public int SquareFeet
{
get { return m_nSqFeet; }
set { m_nSqFeet = value; } // value 為隱含參數
}
}
使用時如同欄位般自然:
House myHouse = new House();
myHouse.SquareFeet = 250; // 呼叫 set
Console.WriteLine(myHouse.SquareFeet); // 呼叫 get
getsetset 中檢查範圍、拒絕無效值索引子讓類別支援 obj[index] 語法,底層邏輯由 get/set 定義。
public string this[int index]
{
get { /* 回傳邏輯 */ }
set { /* 設定邏輯 */ }
}
關鍵點:
this 關鍵字,無自訂名稱ref/outInterfaceName.this 區分class ResolveDNS
{
IPAddress[] m_arrIPs;
public void Resolve(string host)
{
IPHostEntry entry = Dns.GetHostByName(host);
m_arrIPs = entry.AddressList;
}
public IPAddress this[int index]
{
get { return m_arrIPs[index]; }
}
public int Count => m_arrIPs.Length;
}
// 使用方式
var resolver = new ResolveDNS();
resolver.Resolve("www.microsoft.com");
for (int i = 0; i < resolver.Count; i++)
Console.WriteLine(resolver[i]);
編譯需參考 System.Net.dll:csc /r:System.Net.dll dnsresolve.cs
事件讓類別在特定情況發生時通知訂閱者,基於委派實現,支援多播(多訂閱者)。
delegate void EventHandler(string text);public event EventHandler TextOut;TextOut("訊息");+= / -= 操作子public delegate void EventHandler(string strText);
class EventSource
{
public event EventHandler TextOut;
public void TriggerEvent()
{
TextOut?.Invoke("Event triggered"); // C# 6.0 null 條件運算子
}
}
class TestApp
{
static void Main()
{
var src = new EventSource();
src.TextOut += CatchEvent; // 靜態方法訂閱
src.TriggerEvent();
src.TextOut -= CatchEvent; // 取消訂閱
src.TriggerEvent();
var app = new TestApp();
src.TextOut += app.InstanceCatch; // 實例方法訂閱
src.TriggerEvent();
}
static void CatchEvent(string text) => Console.WriteLine(text);
void InstanceCatch(string text) => Console.WriteLine("Instance " + text);
}
事件廣泛應用於 ASP.NET、Windows Forms、WPF 等 UI 架構的按鈕點擊、資料繫結變更等場景。
| 分類 | 修飾符 | 說明 |
|---|---|---|
| 類別修飾符 | abstract | 不可實例化,衍生類必須實作所有抽象成員,不可與 sealed 共存 |
sealed | 密封類別,禁止繼承,.NET Framework 大量使用 | |
| 成員修飾符 | abstract | 無實作,隱含 virtual,衍生類必須 override |
const | 編譯期常數,不可參考變數 | |
event | 宣告事件成員 | |
extern | 外部實作(如 P/Invoke) | |
override | 覆寫 virtual/abstract 成員 | |
readonly | 唯讀欄位,僅能在宣告或建構函式賦值 | |
static | 屬於類別而非實例,適用欄位、方法、屬性、建構函式 | |
virtual | 允許衍生類覆寫 | |
| 存取修飾符 | public | 完全公開 |
protected | 類別本身與衍生類可存取 | |
private | 僅類別內部可存取 | |
internal | 同一組件內公開,跨組件為 private |
internal class Triangle
{
protected int m_a, m_b, m_c; // 衍生類可存取
public Triangle(int a, int b, int c) { ... }
public virtual double Area() { ... } // 可覆寫
}
internal class Prism : Triangle
{
private int m_h; // 僅本類可存取
public Prism(int a, int b, int c, int h) : base(a, b, c) { ... }
public override double Area() { ... } // 覆寫並呼叫 base.Area()
}
internal 限制組件外不可見,protected 讓衍生類存取基類欄位,private 封裝衍生類自有欄位——良好的封裝層次規劃能降低維護成本。
IDisposable 模式in(預設)、ref、out 三種傳遞模式virtual/override 實現執行期多型;new 解決版本衝突掌握這些核心機制,才能設計出健壯、可擴充、易維護的 C# 類別庫。