代码契约:我们是否必须在委托方法中冗余地指定 Contract.Requires(...) 语句?
我打算使用新的 .NET 4 代码契约 功能来进行未来的开发。这让我想知道我们是否必须在方法链中冗余地指定等效的 Contract.Requires(...)
语句。
我认为一个代码示例胜过一千个单词:
public bool CrushGodzilla(string weapon, int velocity)
{
Contract.Requires(weapon != null);
// long code
return false;
}
public bool CrushGodzilla(string weapon)
{
Contract.Requires(weapon != null); // specify contract requirement here
// as well???
return this.CrushGodzilla(weapon, int.MaxValue);
}
对于运行时检查来说这并不重要,因为我们最终总是会遇到需求检查,如果失败我们会得到一个错误。
但是,当我们在第二次重载中没有再次指定合同要求时,这是否被认为是不好的做法?
此外,还将具有编译时检查功能,并且可能还具有代码契约的设计时检查功能。 Visual Studio 2010 中的 C# 似乎尚未提供此功能,但我认为某些语言(如 Spec#)已经提供了该功能。当我们编写代码来调用此类方法并且我们的参数当前可以或将为 null
时,这些引擎可能会给我们提示。
所以我想知道这些引擎是否总是会分析调用堆栈,直到找到具有当前不满足的合同的方法?
此外,在这里我了解了 Contract.Requires(.. .)
和 Contract.Assume(...)
。我想在这个问题的背景下也应该考虑这种差异吗?
I'm intending to use the new .NET 4 Code Contracts feature for future development. This made me wonder if we have to specify equivalent Contract.Requires(...)
statements redundantly in a chain of methods.
I think a code example is worth a thousand words:
public bool CrushGodzilla(string weapon, int velocity)
{
Contract.Requires(weapon != null);
// long code
return false;
}
public bool CrushGodzilla(string weapon)
{
Contract.Requires(weapon != null); // specify contract requirement here
// as well???
return this.CrushGodzilla(weapon, int.MaxValue);
}
For runtime checking it doesn't matter much, as we will eventually always hit the requirement check, and we will get an error if it fails.
However, is it considered bad practice when we don't specify the contract requirement here in the second overload again?
Also, there will be the feature of compile time checking, and possibly also design time checking of code contracts. It seems it's not yet available for C# in Visual Studio 2010, but I think there are some languages like Spec# that already do. These engines will probably give us hints when we write code to call such a method and our argument currently can or will be null
.
So I wonder if these engines will always analyze a call stack until they find a method with a contract that is currently not satisfied?
Furthermore, here I learned about the difference between Contract.Requires(...)
and Contract.Assume(...)
. I suppose that difference is also to consider in the context of this question then?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我认为最好的做法是在每个公共方法上指定所有合同。合同不仅仅是“检查的内容”——它也是有效的文档。如果您调用一个方法,但不知道应用了什么合同,那么在下面得到合同失败会很奇怪:这表明您正在调用的方法中存在错误,而不是您的方法中存在错误。 em> 方法。
请注意,如果您在整个项目中使用 C# 4,则可以考虑使用可选参数和命名参数来避免出现过多的重载。当然,如果您需要从不支持它们的语言调用代码,那么这就没用了。
我强烈怀疑,如果您没有在“默认”重载中指定合同,静态检查器(现在是适用于所有版本的 VS2010)会抱怨合约可能会失败,并且还会建议添加合约。
I think it would be best practice to specify all the contracts on each of the public methods. A contract is more than just "what gets checked" - it's documentation too, effectively. If you call a method but don't know what contract is applied, it would be odd to get a contract failure lower down: that would suggest a bug in the method that you're calling, rather than in your method.
Note that if you're using C# 4 throughout your project, you could consider using optional parameters and named arguments to avoid having so many overloads. That's not useful if you need to call the code from a language which doesn't support them, of course.
I strongly suspect that if you don't specify the contract in the "defaulting" overload, the static checker (which is now available for all versions of VS2010) will complain that the contract might fail, and will also suggest adding the contract in.
它是可用的,但要使其工作,您必须使用 VS2010 Ultimate 版本。
警告:这有点推测,但从我使用它学到的知识来看,它似乎是正确的;
您需要通过您的方法手动传播约束,就像您所做的那样。
代码契约可以从方法外部看到的唯一信息就是您告诉它的信息。它可以检查方法内部的假设和断言,但这种分析不会传播。换句话说,CC 无法“看穿”您的方法,因此它不会自动知道
CrushGodzilla(string)
将要求weapon
为非空。如果使用静态分析,它将使用有关
的外部信息在
,它会建议您添加一个CrushGodzilla(string)
中执行检查,并意识到weapon
不能为空。 >CrushGodzilla(string,int)Requires
非空前提条件。 (非传播是指这些知识不会用于分析程序的其余部分。)尽管已经看过,但实际上我还没有找到任何很好地记录静态分析器的地方。
It is available, but for it to work you have to be using VS2010 Ultimate edition.
Warning: This is a bit speculative, but it seems to be correct from what I've learned using it;
You need to propagate the constraints through your methods manually, like you have done.
The only information that Code Contracts can see from the outside of a method is what you tell it. It can examine assumptions and assertions inside a method, but this analysis does not propagate. In other words, CC cannot "see through" your methods, so it doesn't automatically know that
CrushGodzilla(string)
will requireweapon
to be non-null.If using static analysis, it will perform checks in
CrushGodzilla(string)
and realize thatweapon
cannot be null, using the external information aboutCrushGodzilla(string,int)
, and it will suggest that you add aRequires
non-null precondition. (The non-propagation is the fact that this knowledge won't be used to analyse the rest of the program.)I haven't actually found anywhere that documents that static analyzer very well, despite having looked.