最近,我开始使用Code contracts for .net。在我看来,代码签约本身的想法很棒,但实现起来非常不愉快。
我不喜欢它的主要原因是:
Contract.Require()
这样的方法。 ContractAbbreviator
有很多限制(例如,我不能把它们放在一个单独的程序集中,我不能使用参数),这使得它们不太可用。没有属性,也没有扩展方法,所以我的代码变得非常冗长。例如,如果我只是想检查Dictionary<string, string>
类型的返回值是否为空,我需要添加一个怪物,例如Contract.Ensure(Contract.Result<Dictionary<string, string>> != null)
。它甚至都不可读。ccrewriter
中存在错误 - 它无法咀嚼一半的程序集,并且无法在.net 4.5运行时中存活.net 4.0程序集。Debug.Assert
一样简单 - 您只需将它们添加到您认为需要的任何地方。但事实证明,我需要向静态检查器证明一切,这是肯定的,但检查器有时是愚蠢的,无法解决许多明显的代码结构(如while
)。并且没有任何工具可以对分析仪说“我知道我在做什么,只是忽略这违反合同”。string.NotNullOrEmpty
这包括string != null
。或者,如果我有自己的大程序检查文件路径,我无法向分析器解释它肯定不是null而不是空的。 ContractAbbreviator
属性有点帮助,但所有这些冗长都在那里,它仍然看起来很脏而且很愚蠢。是否存在代码合约的高级替代方案,其缺陷较少?
答案 0 :(得分:13)
我不知道有什么替代方案,但我或许可以解决你的一些问题。我在一个团队中工作,在我们所有的代码中使用契约(~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的使用,我认为进行静态检查而不仅仅是让我的应用程序在客户站点崩溃是一个巨大的优势。这样,我可以在发布产品之前消除应用程序崩溃的风险。也许我误解了你,但我真的不认为你的比较是有道理的。