我已經在MSDN上的CodeContracts forum上發佈了這個消息,但是顯然沒有人知道或者不願意研究這個問題。CodeContracts:假設/斷言的重用?
我試圖減少重複斷言並使其更加可重用,但不幸的是這不起作用,你能解釋爲什麼嗎?
[ContractVerification(false)]
public static class Assert
{
[Conditional("DEBUG")]
public static void GreaterThan<T>(T value, T lowerBound) where T : IComparable<T>
{
Contract.Ensures(value.CompareTo(lowerBound) > 0);
}
[Conditional("DEBUG")]
public static void GreaterThanOrEqual<T>(T value, T lowerBound) where T : IComparable<T>
{
Contract.Ensures(value.CompareTo(lowerBound) >= 0);
}
[Conditional("DEBUG")]
public static void LessThan<T>(T value, T upperBound) where T : IComparable<T>
{
Contract.Ensures(value.CompareTo(upperBound) < 0);
}
[Conditional("DEBUG")]
public static void LessThanOrEqual<T>(T value, T upperBound) where T : IComparable<T>
{
Contract.Ensures(value.CompareTo(upperBound) <= 0);
}
[Conditional("DEBUG")]
public static void NotNull(object value)
{
Contract.Ensures(value != null);
}
[Conditional("DEBUG")]
public static void NotNullOrEmpty(string value)
{
Contract.Ensures(!string.IsNullOrEmpty(value));
}
[Conditional("DEBUG")]
public static void True(bool value)
{
Contract.Ensures(value);
}
[Conditional("DEBUG")]
public static void False(bool value)
{
Contract.Ensures(!value);
}
[Conditional("DEBUG")]
public static void InRange<T>(T value, T lowerBound, T upperBound, ExclusionMode exclusionMode = ExclusionMode.None) where T : IComparable<T>
{
Contract.Ensures(((exclusionMode | ExclusionMode.LowerBound) == ExclusionMode.LowerBound ? value.CompareTo(lowerBound) > 0 : value.CompareTo(lowerBound) >= 0) && ((exclusionMode | ExclusionMode.UpperBound) == ExclusionMode.UpperBound ? value.CompareTo(upperBound) < 0 : value.CompareTo(upperBound) <= 0));
}
}
我改變它到以下,它似乎工作,但顯然通用版本更可取。
[ContractVerification(false)]
public static class Assert
{
[Conditional("DEBUG")]
public static void GreaterThan(int value, int lowerBound)
{
Contract.Ensures(value > lowerBound);
}
[Conditional("DEBUG")]
public static void GreaterThanOrEqual(int value, int lowerBound)
{
Contract.Ensures(value >= lowerBound);
}
[Conditional("DEBUG")]
public static void LessThan(int value, int upperBound)
{
Contract.Ensures(value < upperBound);
}
[Conditional("DEBUG")]
public static void LessThanOrEqual(int value, int upperBound)
{
Contract.Ensures(value <= upperBound);
}
[Conditional("DEBUG")]
public static void NotNull(object value)
{
Contract.Ensures(value != null);
}
[Conditional("DEBUG")]
public static void NotNullOrEmpty(string value)
{
Contract.Ensures(!string.IsNullOrEmpty(value));
}
[Conditional("DEBUG")]
public static void True(bool value)
{
Contract.Ensures(value);
}
[Conditional("DEBUG")]
public static void False(bool value)
{
Contract.Ensures(!value);
}
[Conditional("DEBUG")]
public static void InRange(int value, int lowerBound, int upperBound, ExclusionMode exclusionMode = ExclusionMode.None)
{
Contract.Ensures(((exclusionMode | ExclusionMode.LowerBound) == ExclusionMode.LowerBound ? value > lowerBound : value >= lowerBound) && ((exclusionMode | ExclusionMode.UpperBound) == ExclusionMode.UpperBound ? value < upperBound : value <= upperBound));
}
}
我只是想說明,即使不是一個解決方案,它具有CodeContracts沒有直接的源代碼,但在IL操作呢?
我已經寫道它使用非通用版本,我知道這一點。自從CodeContracts發佈以來,我一直在與CodeContracts合作,並且我知道您的示例不會起作用,靜態檢查器會對這些斷言進行投訴,因爲ContractAbbreviator僅適用於需求,並且從未設計用於確保其他任何內容。在你的例子中,你在合同之後斷言是毫無意義的,斷言的重點是在被調用之後立即檢查另一個函數的輸出。 – 2012-07-30 21:33:55
你的例子工作,因爲靜態檢查器已經驗證輸入,中間沒有函數返回需要斷言的任意值。我不是要求解決方案,而是要求此人告訴我爲什麼通用版本不起作用?爲什麼不能看到它?有什麼限制? – 2012-07-30 21:47:14
你看到這個錯誤。 'ContractAbbreviator'可以同時處理_requires_和_ensures_。只有使用'ContractAbbreviator'屬性才能將方法調用所在的'GreaterThan'中的合約插入。這不是斷言(但你稱它爲'Assert'),它並不是合約之後。這是合同的一部分。在我的例子中'PlusOne'有一個_requires_和一個_ensures_(通過'GreaterThan')。最終,「GreaterThan」永遠不會被調用,只有合約被複制。我告訴過你爲什麼檢查器不能同時使用'CompareTo'和比較運算符。 – Virtlink 2012-07-30 23:25:14