[英]'Design By Contract' in C#
我想在我最新的C#應用程序中通過契約嘗試一點設計,並希望語法類似於:
public string Foo()
{
set {
Assert.IsNotNull(value);
Assert.IsTrue(value.Contains("bar"));
_foo = value;
}
}
我知道我可以從單元測試框架中獲取這樣的靜態方法,但是我想知道這樣的東西是否已經內置於該語言中,或者是否已經存在某種類型的框架。 我可以編寫自己的Assert函數,只是不想重新發明輪子。
C#4.0代碼合同
Microsoft已經在.net框架的4.0版本中發布了一個按合同設計的庫。 該庫最酷的功能之一是它還帶有靜態分析工具(類似於我猜的FxCop),它利用了您對代碼簽訂的合同的詳細信息。
以下是一些Microsoft資源:
以下是其他一些資源:
Spec#是一個流行的微軟研究項目 ,它允許一些DBC結構,比如檢查post和pre條件。 例如,二進制搜索可以使用前置條件和后置條件以及循環不變量來實現。 這個例子還有更多:
public static int BinarySearch(int[]! a, int key)
requires forall{int i in (0: a.Length), int j in (i: a.Length); a[i] <= a[j]};
ensures 0 <= result ==> a[result] == key;
ensures result < 0 ==> forall{int i in (0: a.Length); a[i] != key};
{
int low = 0;
int high = a.Length - 1;
while (low <= high)
invariant high+1 <= a.Length;
invariant forall{int i in (0: low); a[i] != key};
invariant forall{int i in (high+1: a.Length); a[i] != key};
{
int mid = (low + high) / 2;
int midVal = a[mid];
if (midVal < key) {
low = mid + 1;
} else if (key < midVal) {
high = mid - 1;
} else {
return mid; // key found
}
}
return -(low + 1); // key not found.
}
請注意,使用Spec#語言會產生DBC構造的編譯時檢查 ,對我來說,這是利用DBC的最佳方法。 通常,依賴於運行時斷言會成為生產中的頭痛,人們通常會選擇使用異常 。
除了使用外部庫,您在System.Diagnostics中有一個簡單的斷言:
using System.Diagnostics
Debug.Assert(value != null);
Debug.Assert(value == true);
我知道,不是很有用。
.net Fx 4.0中有一個答案:
System.Diagnostics.Contracts
http://msdn.microsoft.com/en-us/library/dd264808.aspx
Contract.Requires(newNumber > 0, “Failed contract: negative”);
Contract.Ensures(list.Count == Contract.OldValue(list.Count) + 1);
查看Moq的代碼,我看到他們使用了一個名為“Guard”的類,它提供了檢查前后條件的靜態方法 。 我覺得這很整潔也很清楚。 它表達了我在代碼中通過合同檢查實現設計時所考慮的內容。
例如
public void Foo(Bar param)
{
Guard.ArgumentNotNull(param);
}
我認為通過合同檢查表達設計是一種巧妙的方式。
試試LinFu的DesignByContract庫:
對於我目前的項目(2010年2月,VS 2008),我選擇http://lightcontracts.codeplex.com/
很簡單,它只是運行時驗證,沒有任何奇怪的復雜性,你不需要從一些'奇怪的'基類派生,沒有AOP,VS集成,它不適用於某些開發人員工作站等。
簡單而復雜。
您可以查看nVentive Umbrella :
using System;
using nVentive.Umbrella.Validation;
using nVentive.Umbrella.Extensions;
namespace Namespace
{
public static class StringValidationExtensionPoint
{
public static string Contains(this ValidationExtensionPoint<string> vep, string value)
{
if (vep.ExtendedValue.IndexOf(value, StringComparison.InvariantCultureIgnoreCase) == -1)
throw new ArgumentException(String.Format("Must contain '{0}'.", value));
return vep.ExtendedValue;
}
}
class Class
{
private string _foo;
public string Foo
{
set
{
_foo = value.Validation()
.NotNull("Foo")
.Validation()
.Contains("bar");
}
}
}
}
我希望驗證擴展是構建器,所以你可以做_foo = value.Validation().NotNull("Foo").Contains("bar").Value;
但事實就是如此(幸運的是它的開源,所以使它成為一個建設者是一個微不足道的變化)。
作為替代解決方案,您可以考慮進行域驗證 。
最后, 作為Oslo的一部分, 新的M語言支持對其范圍和字段的限制,這些限制既轉換為T-SQL驗證又轉換為具有功能驗證測試的CLR類(盡管Oslo在發布后已經很長時間了)。
最簡單的方法,以及.NET Framework本身使用的方法是:
public string Foo()
{
set {
if (value == null)
throw new ArgumentNullException("value");
if (!value.Contains("bar"))
throw new ArgumentException(@"value should contain ""bar""", "value");
_foo = value;
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.