代码之家  ›  专栏  ›  技术社区  ›  IAmCodeMonkey

C语言中的“合同设计”#

  •  35
  • IAmCodeMonkey  · 技术社区  · 16 年前

    我想在我最新的C#应用程序中尝试一下契约式设计,并希望语法类似于:

    public string Foo()
    {
        set {
            Assert.IsNotNull(value);
            Assert.IsTrue(value.Contains("bar"));
            _foo = value;
        }
    }
    

    我知道我可以从单元测试框架中获得这样的静态方法,但我想知道这样的东西是否已经内置到语言中,或者是否已经有某种框架在浮动。我可以编写自己的断言函数,只是不想重新发明轮子。

    11 回复  |  直到 16 年前
        2
  •  23
  •   Community CDub    8 年前

    Spec# microsoft research project 这允许一些DBC构造,比如检查post和前置条件。例如,二进制搜索可以通过前置和后置条件以及循环不变量来实现。 This example and more:

     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的最佳方式。通常,依赖运行时断言会成为生产中的一个难题,人们通常会选择这样做 use exceptions 相反

    other languages Eiffel 也可用于.NET平台。

        3
  •  10
  •   FlySwat    16 年前

    除了使用外部库之外,系统中还有一个简单的断言。诊断:

    using System.Diagnostics
    
    Debug.Assert(value != null);
    Debug.Assert(value == true);
    

        4
  •  7
  •   Majid    10 年前

    在.net Fx 4.0中有一个答案:

    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);
    
        5
  •  2
  •   Hamish Smith    16 年前

    Looking over the code for Moq I saw that they use a class called 'Guard' that provides static methods for checking pre and post conditions . 我认为这很清楚。它表达了我在代码中实现契约式设计检查时的想法。

    例如

    public void Foo(Bar param)
    {
       Guard.ArgumentNotNull(param);
    } 
    

    我认为通过合同检查来表达设计是一种很好的方式。

        6
  •  1
  •   cfeduke    16 年前

    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; 但它就是这样(幸运的是,它的开源使它成为一个构建器是一个微不足道的改变)。

    consider domain validation .

    new M languages , as part of Oslo

        7
  •  1
  •   Tomasz Modelski    15 年前

    对于我目前的项目(2010年2月VS 2008年),我选择了 http://lightcontracts.codeplex.com/

    很简单,它只是运行时验证,没有任何奇怪的复杂性,您不需要从一些“奇怪的”基类派生,没有AOP,VS集成,这在一些开发人员工作站上不起作用,等等。

    简单胜过复杂。

        8
  •  1
  •   Richard C    14 年前

    最直接的方法,也是在.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;
        }
    }