命名慣例
| 目標 | 慣例 | 範例 |
| 類別、介面、列舉、委派、命名空間 | PascalCase | CustomerOrder, IRepository |
| 方法、屬性、事件、公開欄位 | PascalCase | CalculateTotal(), FirstName |
| 區域變數、參數、私有欄位 | camelCase | totalAmount, customerId |
| 常數 | PascalCase | MaxRetryCount |
| 介面前綴 | I + PascalCase | IUserService |
| 非同步方法後綴 | Async | GetDataAsync() |
禁用:匈牙利標記法(strName, nAge)、底線前綴(_field 除非團隊共識)、單字母變數(迴圈索引 i 除外)。
格式與排版
- 縮進:Tab**(非空白鍵)。
- 大括號
{ } 獨立一行(Allman 風格)。
- 運算子前後、逗號後、分號後加一空格。
- 邏輯區塊間以單一空行分隔。
- 單檔建議 < 400 行,單一方法 < 25 行,超過即拆分。
// Good
if (isValid)
{
DoSomething();
}
// Bad
if(isValid){DoSomething();}
良好設計習慣
- 單一職責:一個方法只做一件事。拆分「存檔」與「發送通知」為兩個方法。
- 意圖揭露命名:
SavePhoneNumber() 優於 SaveData() + 註解。
- 使用 C# 內建別名:
int、string、object 而非 Int32、String、Object。
- 消除魔術數字/字串:改用
const、enum、資源檔。
- 避免成員變數共享狀態:偏好區域變數傳遞,減少副作用。
- Enum 替代字串/數字狀態:
MailType.Html 而非 "Html"。
- 封裝欄位:
private 欄位 + public 屬性。
- 相對路徑:勿硬編碼
C:\,使用 AppDomain.CurrentDomain.BaseDirectory 或設定檔。
- 啟動自檢:檢查必要檔案、資料庫連線、設定檔,缺失給予友善提示並建立預設值。
- 錯誤訊息使用者友善 + 開發者詳盡:UI 顯示「更新失敗,請確認帳號密碼」,日誌記錄完整堆疊、時間、參數。
註解原則
- 「好代碼勝過壞註解」:命名清晰即可減少註解。
- XML 文件註解(
///)用於公開 API,供 IntelliSense 顯示。
- 複雜演算法、商業規則、暫時性 Hack 必須註解「為什麼」而非「做什麼」。
- 拼寫、標點、語法正確;過期註解立即刪除。
異常處理鐵律
| 原則 | 正確做法 | 錯誤做法 |
| 捕捉具體異常 | catch (FileNotFoundException ex) | catch (Exception ex) 吞沒錯誤 |
| 不隱藏異常 | 記錄後 throw; 重拋或包裝拋出 | catch { return null; } |
| 不濫用 try-catch | 僅在預期特定失敗處使用 | 每個方法都包 try-catch |
| 應用層級統一處理 | Application.ThreadException、TaskScheduler.UnobservedTaskException | 無全域處理導致崩潰無日誌 |
| 自訂異常繼承 | class BizException : Exception(非 SystemException) | 繼承 SystemException |
程式碼審查清單
- 命名是否符合慣例且揭露意圖?
- 方法是否過長?類別是否過大?
- 是否有重複代碼可提煉?
- 是否正確使用
using/IDisposable 釋放資源?
- 是否有潛在 NullReference、多執行緒競態?
- 單元測試覆蓋核心邏輯?
- 異常處理是否符合上述鐵律?