代碼契約源自微軟研究院的「契約式設計」理念。傳統開發中,開發者僅通過註釋說明方法參數要求,但無法強制調用者遵守。.NET 4.0 引入的 System.Diagnostics.Contracts 命名空間,提供了編譯時靜態檢查與運行時動態驗證的雙重保障,類似 C++ 的斷言機制但功能更豐富,能有效提升代碼健壯性與可維護性。
所有契約均定義於靜態類 CodeContract 中,主要包含前置條件、後置條件與物件不變量三大類。
在方法體開頭調用,驗證輸入參數合法性。
// 僅在定義 CONTRACTS_FULL 或 CONTRACTS_PRECONDITIONS 符號時生效(通常僅 Debug 模式)
CodeContract.Requires(x >= 0);
// 無視編譯開關,Debug/Release 皆生效
CodeContract.RequiresAlways(x >= 0);
雖寫在方法開頭,但語義上在方法成功返回或拋出異常時驗證。
// 方法正常結束時必須為真
CodeContract.Ensures(z != null);
// 方法拋出異常時,確保特定狀態成立
CodeContract.EnsuresOnThrow<SpecificException>(z != null);
確保物件所有公共方法返回時,特定條件始終成立。需標註 [ContractInvariantMethod] 屬性,方法無參無返回值。
[ContractInvariantMethod]
void ObjectInvariant() {
CodeContract.Invariant(this.someData >= 0);
CodeContract.Invariant(this.collection != null);
}
Contract.Assert(condition),失敗時觸發 Debug.Assert(false) 並調用 Environment.FailFast()。Contract.Assume(condition),告訴靜態分析器「此處假設條件為真」,用於無法編譯驗證但運行期保證成立的場景。Contract.ForAll、Contract.Exists,用於集合元素的批量條件驗證。IContract 並關聯介面,同樣適用於抽象方法。Requires(僅 Debug),安全關鍵檢查用 RequiresAlways。ObjectInvariant,避免邏輯分散。代碼契約並非單元測試的替代品,而是補充。它將「文檔化的假設」轉化為「可驗證的規約」,讓介面契約成為代碼的一等公民,是構建高可靠 .NET 系統的關鍵基礎設施。