簡體   English   中英

C#中的“按合同設計”

[英]'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的最佳方法。 通常,依賴於運行時斷言會成為生產中的頭痛,人們通常會選擇使用異常

還有其他語言將DBC概念作為第一類構造包含在內,即Eiffel也可用於.NET平台。

除了使用外部庫,您在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);
} 

我認為通過合同檢查表達設計是一種巧妙的方式。

您可以使用尖銳架構的“按合同設計”實施。 以下是鏈接: http//code.google.com/p/sharp-architecture/

問候,

試試LinFu的DesignByContract庫:

http://www.codeproject.com/KB/cs/LinFu_Part5.aspx

對於我目前的項目(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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM