none
vs 2010 版本中的契约式编程 RRS feed

  • 问题

  • 使用 vs 2010 中文试用版 编译 Yi Zhang 老师的例子 ,例子博客地址:http://blogs.msdn.com/b/yizhang/archive/2009/08/20/net-4-0-design-by-contracts.aspx

    编译后 所有的契约好像都没有效果代码如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Diagnostics.Contracts;
    
    namespace 测试
    {
      /// <summary>
      /// 一个契约式编程的案例。
      /// </summary>
      public class WordList
      {
        private List<string> _words;
    
        public WordList(int capacity)
        {
          Contract.Requires(capacity > 0);
          _words = new List<string>(capacity);
        }
    
        public void Insert(string word)
        {
          Contract.Requires(word != null);//检测输入的参数是否复合规则。
          Contract.Ensures(Contract.OldValue<int>(_words.Count) + 1 == _words.Count); //这里是检测函数的出口,以保证正确。注意OldValue不完全代表函数的参数,也可以是其它的变量。
          Contract.EnsuresOnThrow<ApplicationException>(Contract.OldValue<int>(_words.Count) == _words.Count);//这里表示如果是以抛出表达式相同的异常为函数的出口,那么必须保证表达式中条件。
    
          int i;
          for (i = 0; i < _words.Count; i++)
          {
            int compare= string.Compare(word,_words[i]);
            if (compare > 0)
              break;
            else if (compare == 0)
              throw new ApplicationException("Already exist!");
          }
    
          _words.Insert(i, word);
        }
    
        [ContractInvariantMethod]
        internal void Invariant()
        {
          Contract.Invariant(Contract.ForAll(_words, w => w != null)); //不能有空的字符串。
    
          Contract.Invariant(IsAscending()); //表示必须满足升序条件。
        }
    
        [Pure]//这个表示让契约检测来忽略此方法,表示告诉契约这个函数不会对这个对象的元素产生任何副作用。
        internal bool IsAscending()
        {
          bool isAscending = true;
          for (int i = 1; i < _words.Count; ++i)
          {
            if (string.Compare(_words[i - 1], _words[i]) > 0)
            {
              isAscending = false;
              break;
            }
          }
    
          return isAscending;
        }
      }
    
      class 契约式编程
      {
        static void Main(string[] args)
        {
          //这里有意违反契约规定来测试用。
          WordList wl = new WordList(0);
    
          wl.Insert("Hello");
          wl.Insert("World");
    
          Console.ReadKey(true);
        }
      }
    }
    
    
     
    

    实际在反编译中,没有任何 契约的代码,而且运行时也不提示错误。

    .class public auto ansi beforefieldinit WordList
      extends [mscorlib]System.Object
    {
      .method public hidebysig specialname rtspecialname instance void .ctor(int32 capacity) cil managed
      {
        .maxstack 8
        L_0000: ldarg.0 
        L_0001: call instance void [mscorlib]System.Object::.ctor()
        L_0006: nop 
        L_0007: nop 
        L_0008: ldarg.0 
        L_0009: ldarg.1 
        L_000a: newobj instance void [mscorlib]System.Collections.Generic.List`1<string>::.ctor(int32)
        L_000f: stfld class [mscorlib]System.Collections.Generic.List`1<string> 测试.WordList::_words
        L_0014: nop 
        L_0015: ret 
      }
    
      .method public hidebysig instance void Insert(string word) cil managed
      {
        .maxstack 3
        .locals init (
          [0] int32 i,
          [1] int32 compare,
          [2] bool CS$4$0000)
        L_0000: nop 
        L_0001: ldc.i4.0 
        L_0002: stloc.0 
        L_0003: br.s L_0041
        L_0005: nop 
        L_0006: ldarg.1 
        L_0007: ldarg.0 
        L_0008: ldfld class [mscorlib]System.Collections.Generic.List`1<string> 测试.WordList::_words
        L_000d: ldloc.0 
        L_000e: callvirt instance !0 [mscorlib]System.Collections.Generic.List`1<string>::get_Item(int32)
        L_0013: call int32 [mscorlib]System.String::Compare(string, string)
        L_0018: stloc.1 
        L_0019: ldloc.1 
        L_001a: ldc.i4.0 
        L_001b: cgt 
        L_001d: ldc.i4.0 
        L_001e: ceq 
        L_0020: stloc.2 
        L_0021: ldloc.2 
        L_0022: brtrue.s L_0026
        L_0024: br.s L_0053
        L_0026: ldloc.1 
        L_0027: ldc.i4.0 
        L_0028: ceq 
        L_002a: ldc.i4.0 
        L_002b: ceq 
        L_002d: stloc.2 
        L_002e: ldloc.2 
        L_002f: brtrue.s L_003c
        L_0031: ldstr "Already exist!"
        L_0036: newobj instance void [mscorlib]System.ApplicationException::.ctor(string)
        L_003b: throw 
        L_003c: nop 
        L_003d: ldloc.0 
        L_003e: ldc.i4.1 
        L_003f: add 
        L_0040: stloc.0 
        L_0041: ldloc.0 
        L_0042: ldarg.0 
        L_0043: ldfld class [mscorlib]System.Collections.Generic.List`1<string> 测试.WordList::_words
        L_0048: callvirt instance int32 [mscorlib]System.Collections.Generic.List`1<string>::get_Count()
        L_004d: clt 
        L_004f: stloc.2 
        L_0050: ldloc.2 
        L_0051: brtrue.s L_0005
        L_0053: ldarg.0 
        L_0054: ldfld class [mscorlib]System.Collections.Generic.List`1<string> 测试.WordList::_words
        L_0059: ldloc.0 
        L_005a: ldarg.1 
        L_005b: callvirt instance void [mscorlib]System.Collections.Generic.List`1<string>::Insert(int32, !0)
        L_0060: nop 
        L_0061: ret 
      }
    
      .method assembly hidebysig instance void Invariant() cil managed
      {
        .maxstack 8
        L_0000: nop 
        L_0001: ret 
      }
    
      .method assembly hidebysig instance bool IsAscending() cil managed
      {
        .maxstack 3
        .locals init (
          [0] bool isAscending,
          [1] int32 i,
          [2] bool CS$1$0000,
          [3] bool CS$4$0001)
        L_0000: nop 
        L_0001: ldc.i4.1 
        L_0002: stloc.0 
        L_0003: ldc.i4.1 
        L_0004: stloc.1 
        L_0005: br.s L_003b
        L_0007: nop 
        L_0008: ldarg.0 
        L_0009: ldfld class [mscorlib]System.Collections.Generic.List`1<string> 测试.WordList::_words
        L_000e: ldloc.1 
        L_000f: ldc.i4.1 
        L_0010: sub 
        L_0011: callvirt instance !0 [mscorlib]System.Collections.Generic.List`1<string>::get_Item(int32)
        L_0016: ldarg.0 
        L_0017: ldfld class [mscorlib]System.Collections.Generic.List`1<string> 测试.WordList::_words
        L_001c: ldloc.1 
        L_001d: callvirt instance !0 [mscorlib]System.Collections.Generic.List`1<string>::get_Item(int32)
        L_0022: call int32 [mscorlib]System.String::Compare(string, string)
        L_0027: ldc.i4.0 
        L_0028: cgt 
        L_002a: ldc.i4.0 
        L_002b: ceq 
        L_002d: stloc.3 
        L_002e: ldloc.3 
        L_002f: brtrue.s L_0036
        L_0031: nop 
        L_0032: ldc.i4.0 
        L_0033: stloc.0 
        L_0034: br.s L_004d
        L_0036: nop 
        L_0037: ldloc.1 
        L_0038: ldc.i4.1 
        L_0039: add 
        L_003a: stloc.1 
        L_003b: ldloc.1 
        L_003c: ldarg.0 
        L_003d: ldfld class [mscorlib]System.Collections.Generic.List`1<string> 测试.WordList::_words
        L_0042: callvirt instance int32 [mscorlib]System.Collections.Generic.List`1<string>::get_Count()
        L_0047: clt 
        L_0049: stloc.3 
        L_004a: ldloc.3 
        L_004b: brtrue.s L_0007
        L_004d: ldloc.0 
        L_004e: stloc.2 
        L_004f: br.s L_0051
        L_0051: ldloc.2 
        L_0052: ret 
      }
    
    
      .field private class [mscorlib]System.Collections.Generic.List`1<string> _words
    
    }
    
    
    

    请高人解答,是不是我漏了什么设置之类的东西。 

    2010年8月9日 5:42

答案

  • 默认情况下,Visual Studio 2010 / Framework 4.0 仅仅提供了 Contract 类型,但没有提供相应的 BinaryRewriter。这个是必须的,因为没有这个工具的话,MSBuild 不会执行链接后的二进制重写任务,Contract 当然不会生效。您可以去 MSDN DevLab 上下载一个 Code Contract 的安装 MSI,安装就可以了。

    另外,安装完之后,就可以在任何一个 Visual Studio 2010 项目属性中看到 Code Contracts 选项卡。


    Mark Zhou
    2010年8月10日 8:44

全部回复

  • 默认情况下,Visual Studio 2010 / Framework 4.0 仅仅提供了 Contract 类型,但没有提供相应的 BinaryRewriter。这个是必须的,因为没有这个工具的话,MSBuild 不会执行链接后的二进制重写任务,Contract 当然不会生效。您可以去 MSDN DevLab 上下载一个 Code Contract 的安装 MSI,安装就可以了。

    另外,安装完之后,就可以在任何一个 Visual Studio 2010 项目属性中看到 Code Contracts 选项卡。


    Mark Zhou
    2010年8月10日 8:44
  •  非常感谢。
    2010年8月11日 3:38