.NET 4.0 將代碼契約整合進 `mscorlib.dll` (位於 `System.Diagnostics.Contracts`),提供**編譯時靜態分析**與**運行時動態驗證**雙重保障。本文詳細分類七大契約類型,並給出完整類別實現範例。
| 類型 | 方法 | 觸發時機 | 用途 |
|---|---|---|---|
| 前置條件 | `Contract.Requires` / `RequiresAlways` | 方法進入 | 參數驗證、前置狀態檢查 |
| 後置條件 | `Contract.Ensures` / `EnsuresOnThrow` | 方法退出 (正常/異常) | 返回值驗證、副作用保證 |
| 物件不變量 | `Contract.Invariant` (在 `[ContractInvariantMethod]` 中) | 每個 public 方法退出 | 實例一致性約束 (如分母非零) |
| 斷言 | `Contract.Assert` | 到達該行 | 內部邏輯假設驗證 |
| 假定 | `Contract.Assume` | 靜態分析時 | 告訴分析器「此處假設為真」,無法編譯驗證時使用 |
| 量詞 | `Contract.ForAll` / `Exists` | 集合遍歷 | 批量元素條件驗證 |
| 介面/抽象契約 | 獨立類實現 `IContract` + 屬性關聯 | 介面/抽象方法調用 | 為無方法體的介面/抽象成員添加契約 |
public Rational(int numerator, int denominator) {
Contract.Requires(denominator != 0); // 僅定義 CONTRACTS_FULL 時生效
Contract.RequiresAlways(numerator >= 0); // 無視編譯開關
this.numerator = numerator;
this.denominator = denominator;
}
public int Denominator {
get {
Contract.Ensures(Contract.Result<int>() != 0); // 返回值契約
return this.denominator;
}
}
雖寫在 `get` 開頭,實際在**返回給調用者前**驗證。
[ContractInvariantMethod]
protected void ObjectInvariant() {
Contract.Invariant(this.denominator != 0);
Contract.Invariant(this.numerator >= 0);
}
void Process(Data d) {
Contract.Assert(d != null); // 失敗 → Debug.Assert(false) → Environment.FailFast()
Contract.Assume(d.IsValid); // 靜態分析器假設為真,運行時不檢查
// ...
}
[ContractClass(typeof(ICalculatorContract))]
public interface ICalculator {
int Add(int x, int y);
}
[ContractClassFor(typeof(ICalculator))]
internal sealed class ICalculatorContract : ICalculator {
public int Add(int x, int y) {
Contract.Requires(x >= 0);
Contract.Requires(y >= 0);
Contract.Ensures(Contract.Result<int>() >= 0);
return default; // 僅為契約,不實際執行
}
}

using System.Diagnostics.Contracts;
public struct Rational {
private readonly int numerator, denominator;
public Rational(int numerator, int denominator) {
Contract.Requires(denominator != 0);
this.numerator = numerator;
this.denominator = denominator;
}
public int Numerator {
get {
Contract.Ensures(Contract.Result<int>() == this.numerator);
return numerator;
}
}
public int Denominator {
get {
Contract.Ensures(Contract.Result<int>() != 0);
return denominator;
}
}
[ContractInvariantMethod]
private void ObjectInvariant() {
Contract.Invariant(denominator != 0);
}
public static Rational operator +(Rational a, Rational b) {
Contract.Ensures(Contract.Result<Rational>().Denominator != 0);
return new Rational(a.numerator * b.denominator + b.numerator * a.denominator,
a.denominator * b.denominator);
}
}
代碼契約將「文檔化假設」昇級為「可驗證規約」,是構建高可靠 .NET 類庫的核心基礎設施。