最近,我开始使用.net的代码合同.在我看来,代码签约本身的想法很棒,但实现起来非常不愉快.
我不喜欢它的主要原因是:
我只能使用像Contract.Require()
我的程序里面的方法.ContractAbbreviator
s有很多限制(比如,我不能将它们放在一个单独的程序集中,我不能使用参数),这使得它们的可用性降低.没有属性,也没有扩展方法,所以我的代码变得非常冗长.例如,如果我只是想检查我的返回值类型Dictionary
是否为null,我需要添加一个怪物,如Contract.Ensure(Contract.Result
.它甚至都不可读.
静态分析仪发出了很多错误警报,我花了更多时间来关闭它而不是解决实际问题.
这非常慢.尽管它有一些缓存,但即使是一个小项目也需要几分钟的时间来分析,这使得增量修复变得毫无用处.这只需要太长时间.
有一些错误ccrewriter
- 它不能咀嚼一半的程序集,并且它无法在.net 4.5运行时中存活.net 4.0程序集.
有运行时/静态检查器二元论.当我刚刚开始时,我认为这很简单Debug.Assert
- 你只需将它们添加到你认为需要的任何地方.但事实证明,我需要向静态检查器证明一切,这是肯定的,但检查器有时是愚蠢的,无法解决许多明显的代码结构(如while
).并且没有任何工具可以对分析仪说"我知道我在做什么,只是忽略这违反合同".
你无法联系条件.例如,没有办法向静态分析器解释如果我检查string.NotNullOrEmpty
这包括string != null
.或者,如果我有自己的大程序检查文件路径,我无法向分析器解释它肯定不是null而不是空的.该ContractAbbreviator
属性帮助一点点,但所有这些冗长去那里,它仍然看起来肮脏和愚蠢的.
代码合同的开发速度非常慢,即使它现在是开源的,据我所知,代码库处于不良状态.
代码合同是否有任何先进的替代方案,缺陷较少?
我不知道有什么替代方案,但我或许可以解决你的一些问题.我在一个团队中工作,该团队在我们的所有代码(~1000个模块)中使用契约,并在每个签入和VS中运行静态分析.
代码丑陋.我们为(几乎)所有东西提供单独的接口,以及实现这些的抽象类,由ContractClass和ContractClassFor属性连接.合同在抽象的ContractClassFor-classes中,这使得实际的实现代码几乎不受代码契约的影响.
静态分析仪的缓慢通常是由于合同不够,这迫使分析仪做更多的工作来确定合同是否可以被打破.
静态检查程序错误警报.我有一些,但在一定程度上它已成为一个问题.同样,如果您的合同太少,静态检查程序可能无法及时完成分析.
可以使用这些MSBuild选项调试静态分析器慢度,这将显示哪些方法花费最多时间进行分析.
msbuild myproject.sln /p:CodeContractsExtraAnalysisOptions="-show progress -stats=!! -stats slowMethods"
如果你确定某些条件总是成立,那么你可以使用Contract.Assume(condition)来指示静态检查器假设是这种情况.例如.
Contract.Assume(mystring != null && mystring != "")
或者只是 Contract.Assume(!string.IsNullOrEmpty(mystring))
关于Debug.Assert的使用,我认为进行静态检查而不仅仅是让我的应用程序在客户站点崩溃是一个巨大的优势.这样,我可以在发布产品之前消除应用程序崩溃的风险.也许我误解了你,但我真的不认为你的比较是有道理的.