积极答复者
vs 2010 版本中的契约式编程

问题
-
使用 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 }
请高人解答,是不是我漏了什么设置之类的东西。
答案
-
默认情况下,Visual Studio 2010 / Framework 4.0 仅仅提供了 Contract 类型,但没有提供相应的 BinaryRewriter。这个是必须的,因为没有这个工具的话,MSBuild 不会执行链接后的二进制重写任务,Contract 当然不会生效。您可以去 MSDN DevLab 上下载一个 Code Contract 的安装 MSI,安装就可以了。
另外,安装完之后,就可以在任何一个 Visual Studio 2010 项目属性中看到 Code Contracts 选项卡。
Mark Zhou- 已标记为答案 WCF痴迷者 2010年8月11日 3:37
全部回复
-
默认情况下,Visual Studio 2010 / Framework 4.0 仅仅提供了 Contract 类型,但没有提供相应的 BinaryRewriter。这个是必须的,因为没有这个工具的话,MSBuild 不会执行链接后的二进制重写任务,Contract 当然不会生效。您可以去 MSDN DevLab 上下载一个 Code Contract 的安装 MSI,安装就可以了。
另外,安装完之后,就可以在任何一个 Visual Studio 2010 项目属性中看到 Code Contracts 选项卡。
Mark Zhou- 已标记为答案 WCF痴迷者 2010年8月11日 3:37