前言
本文為系列第三部分,涵蓋第 34-66 條規範,聚焦繼承與多型、介面設計、泛型使用、資源管理、除錯支援等進階主題。
繼承與多型規範
| # | 規範 | 說明 |
| 34 | 避免 new 隱藏,用 override | 明確表達多型意圖 |
| 35 | 非密封類別的 public/protected 方法標記 virtual | 預設可擴展,封裝變化點 |
| 36 | 除非互操作,禁用 unsafe | 類型安全優先 |
| 37 | 避免強制轉型,用 as 防禦性轉型 | 失敗回傳 null 而非拋例外 |
as 防禦性轉型範例
Dog dog = new GermanShepherd();
GermanShepherd shepherd = dog as GermanShepherd;
if (shepherd != null) { ... }
委派與事件模式
| # | 規範 | 關鍵點 |
| 38 | 委派發佈前複製到區域變數 | 避免並發競態 |
| 38b | 調用前檢查 null | 標準事件引發模式 |
| 39 | 不用 public 事件欄位,用事件存取器 | 封裝增減訂閱邏輯 |
| 40 | 用 EventsHelper 安全發佈事件 | 參考 Programming .NET Components |
標準事件引發模式
public class MySource {
public event EventHandler MyEvent;
public void FireEvent() {
EventHandler temp = MyEvent; // 複製避免競態
if (temp != null)
temp(this, EventArgs.Empty);
}
}
事件存取器封裝
public class MySource {
MyDelegate m_SomeEvent;
public event MyDelegate SomeEvent {
add { m_SomeEvent += value; }
remove { m_SomeEvent -= value; }
}
}
介面設計鐵律
| # | 規範 | 說明 |
| 41 | 永遠使用介面 | 參考 Programming .NET Components Ch1,3 |
| 42 | 方法/屬性比 ≥ 2:1 | 行為豐富於資料 |
| 43 | 避免單一成員介面 | 除非標記介面 |
| 44 | 介面成員數 3-5 為宜 | 單一職責、內聚度高 |
| 45 | 介面成員 ≤ 20(實際極限 ~12) | 過大即拆分 |
| 46 | 避免事件作為介面成員 | 事件屬實作細節 |
| 47 | 避免抽象方法,用介面替代 | 介面更靈活、支援多實作 |
| 48 | 類別階層暴露介面 | 參考 Ch3 |
| 49 | 優先使用明確介面實作 | 參考 Ch3,避免命名衝突 |
| 50 | 防禦性查詢介面支援 | 用 as 檢查,勿假設 |
防禦性介面查詢
SomeType obj1 = GetObject();
IMyInterface obj2 = obj1 as IMyInterface;
if (obj2 != null) {
obj2.Method1();
} else {
// 處理不支援介面情況
}
字串與資源管理
| # | 規範 |
| 51 | 面向使用者字串用資源檔,禁硬編碼 |
| 52 | 部署相關字串(連線字串等)用設定檔 |
| 53 | 長字串建構用 StringBuilder |
結構體設計
| # | 規範 |
| 54 | 避免在結構體定義方法 |
| 54a | 參數化建構子鼓勵使用 |
| 54b | 運算子多載允許 |
靜態建構與繫結
| # | 規範 |
| 55 | 提供靜態欄位時,必提供靜態建構子 |
| 56 | 優先早期繫結,避免晚期繫結 |
診斷與流程控制
| # | 規範 |
| 57 | 應用程式啟用日誌與追蹤 |
| 58 | 禁用 goto(switch fall-through 除外) |
| 59 | switch 必有 default + Assert |
switch 防禦性預設
int number = SomeMethod();
switch (number) {
case 1: Trace.WriteLine("Case 1"); break;
case 2: Trace.WriteLine("Case 2"); break;
default: Debug.Assert(false); break;
}
this / base 使用限制
| # | 規範 |
| 60 | 僅在建構子鏈呼叫另一建構子時用 this |
| 61 | 僅解決名稱衝突或呼叫基底建構子時用 base |
正確 this 用法
public class MyClass {
public MyClass(string message) { }
public MyClass() : this("hello") { } // 建構子鏈
}
正確 base 用法
public class GermanShepherd : Dog {
public GermanShepherd(string name) : base(name) { } // 基底建構子
public override void Bark(int howLong) {
base.Bark(howLong); // 基底實作延伸
}
}
Dispose/Finalize 模式
| # | 規範 |
| 62 | 依 Programming .NET Components Ch4 模板實作 |
泛型最佳實踐
| # | 規範 | 範例 |
| 63 | 泛型代碼避免與 Object 轉型,用約束或 as | where T : SomeClass |
| 64 | 泛型介面不定義約束,用強型別介面繼承 | ICustomerList : IList<Customer> |
| 65 | 介面中不定義方法層級約束 | |
| 66 | 資料結構優先使用泛型 | List<T> 而非 ArrayList |
泛型約束正確範例
// 避免
class MyClass {
void SomeMethod(T t) {
object temp = t;
SomeClass obj = (SomeClass)temp; // 裝箱+轉型開銷
}
}
// 正確:型別約束
class MyClass where T : SomeClass {
void SomeMethod(T t) {
SomeClass obj = t; // 直接指派,零開銷
}
}
介面約束替代方案
// 避免:介面層級約束
public interface IList where T : Customer { ... }
// 正確:強型別介面繼承
public interface ICustomerList : IList { ... }
總結
第三部分規範深入核心架構決策:介面導向設計、委派/事件執行緒安全、泛型型別系統善用、資源確定性釋放。這些準則直接決定系統的擴充性、穩定度與效能上限。建議列入程式碼審查核心清單,並以 Roslyn Analyzer 自動化執行關鍵規則(如 Dispose 模式、泛型約束、介面設計)。