通过合同编程时,函数或方法首先检查其前提是否已满足,然后才开始履行其职责,对吗?两个最重要的方式做这些检查是通过assert和exception.
你觉得哪一个更好?
请参阅此处的相关问题
什么是什么时候没有必要检查空?
我最近一直在研究的许多继承代码都有空检查令人作呕.Null检查普通函数,对表示非空返回的API调用进行空检查等.在某些情况下,空检查是合理的,但在许多地方,null不是合理的期望.
我听过很多论点,从"你不能相信其他代码"到"总是防守程序"到"直到语言保证我的非空值,我总会检查." 我当然同意这些原则中的许多原则,但我发现过多的空值检查会导致其他通常违反这些原则的问题.顽强的空检查真的值得吗?
通常,我观察到过多的空检查代码实际上质量较差,而不是质量较高.许多代码似乎都专注于空检查,开发人员已经忽略了其他重要的特性,例如可读性,正确性或异常处理.特别是,我看到很多代码忽略了std :: bad_alloc异常,但对a进行了空检查new.
在C++中,由于解除引用空指针的不可预测行为,我在某种程度上理解这一点; 在Java,C#,Python等中更优雅地处理null dereference.我刚刚看到了警惕的空检查的不良例子,还是真的有什么东西可以解决这个问题?
这个问题旨在与语言无关,尽管我主要对C++,Java和C#感兴趣.
我见过的一些空检查的例子似乎过多,包括:
这个例子似乎是非标准编译器的原因,因为C++规范说失败的新抛出异常.除非您明确支持不合规的编译器,否则这有意义吗?这确实让任何意义的,如Java或C#(甚至C++/CLR)托管语言?
try {
MyObject* obj = new MyObject();
if(obj!=NULL) {
//do something
} else {
//??? most code I see has log-it and move on
//or it repeats what's in the exception handler
}
} catch(std::bad_alloc) {
//Do something? normally--this code is wrong as it allocates
//more memory and will likely fail, such as writing to a log file.
} …Run Code Online (Sandbox Code Playgroud) 有没有办法向ReSharper表明由于按合同设计需要检查,不会出现空引用?例如,以下代码将Possible 'null' assignment to entity marked with 'NotNull' attribute在第7行和第8行的ReSharper中引发warning():
private Dictionary<string, string> _Lookup = new Dictionary<string, string>();
public void Foo(string s)
{
Contract.Requires(!String.IsNullOrEmpty(s));
if (_Lookup.ContainsKey(s))
_Lookup.Remove(s);
}
Run Code Online (Sandbox Code Playgroud)
真正奇怪的是,如果删除该Contract.Requires(...)行,ReSharper消息就会消失.
更新
我通过ExternalAnnotations找到了解决方案,Mike也在下面提到过.以下是如何在Microsoft.Contracts中为函数执行此操作的示例:
Microsoft.Contracts在ExternalAnnotationsReSharper目录下调用的目录.Microsoft.Contracts.xml并填充如下:<assembly name="Microsoft.Contracts">
<member name="M:System.Diagnostics.Contracts.Contract.Requires(System.Boolean)">
<attribute ctor="M:JetBrains.Annotations.AssertionMethodAttribute.#ctor"/>
<parameter name="condition">
<attribute ctor="M:JetBrains.Annotations.AssertionConditionAttribute.#ctor(JetBrains.Annotations.AssertionConditionType)">
<argument>0</argument>
</attribute>
</parameter>
</member>
</assembly>
Run Code Online (Sandbox Code Playgroud)
c# resharper design-by-contract code-contracts microsoft-contracts
最近我与一位同事就单元测试进行了一次有趣的讨论.当合同发生变化时,我们正在讨论何时维持单元测试的效率降低.
也许任何人都可以告诉我如何解决这个问题.让我详细说明:
所以我们假设有一个类可以做一些漂亮的计算.合同说它应该计算一个数字,或者当它由于某种原因失败时返回-1.
我有合同测试谁测试.在我所有的其他测试中,我将这个漂亮的计算器存在.
所以现在我改变了契约,只要它无法计算就会抛出一个CannotCalculateException.
我的合同测试将失败,我将相应地修复它们.但是,我所有的模拟/存根对象仍将使用旧的合同规则.这些测试将成功,而他们不应该!
提出的问题是,凭借对单元测试的这种信念,可以对这些变化有多少信心......单元测试成功,但在测试应用程序时会出现错误.使用这个计算器的测试需要修复,这需要花费时间,甚至可能很多时候被抄袭/嘲笑......
你觉得这个案子怎么样?我从来没有想过它.在我看来,单元测试的这些变化是可以接受的.如果我不使用单元测试,我也会在测试阶段(测试人员)看到这样的错误.然而,我没有足够的信心指出什么会花费更多的时间(或更少).
有什么想法吗?
在发布这个问题并阅读那个问题后,我意识到知道一个方法是否应该返回null是非常重要的,或者如果这被认为是错误条件并且应该抛出异常.还有一个很好的讨论,何时返回'null'或抛出异常.
我正在写一个方法,我已经知道如果我想返回null或抛出异常,表达我的决定的最佳方式是什么,换句话说,记录我的合同?
我能想到的一些方法:
我主要讨论java,但它也可能适用于其他语言:为什么有一种正式的方式来表达是否会抛出异常(throws关键字)但是没有正式的方式来表达是否可能返回null?
为什么没有这样的东西:
public notnull Object methodWhichCannotReturnNull(int i) throws Exception
{
return null; // this would lead to a compiler error!
}
Run Code Online (Sandbox Code Playgroud)
表达合同的方式有很多种:
几年前,我做了一个关于Java的DbC包的调查,我对它们中的任何一个都不满意.不幸的是,我没有对我的发现做好记录,我认为事情已经发生了变化.有人会关心比较和对比不同的Java DbC包吗?
我希望在工作中开始在大量基于Python的项目上使用DBC,并且想知道其他人对它有什么经验.到目前为止,我的研究结果如下:
我的问题是:您是否将DBC与Python一起用于成熟的生产代码?它的效果如何/值得努力?你会推荐哪些工具?
这是我的问题.我是契约设计的忠实粉丝,我正在使用这个概念,特别是在开发可供其他开发人员使用的库时.我刚刚发现了一种新的方法,即:Contract.Requires而不是Exception:所以不要:
public void SomeMethod(string name){
if(name==null) throw new NullArgumentException("Null values not supported");
}
Run Code Online (Sandbox Code Playgroud)
我现在有:
public void SomeMethod(string name){
Contract.Requires(name != null);
}
Run Code Online (Sandbox Code Playgroud)
编辑:我在调试模式下在VS2010下工作.
问题:Contract.Requires什么都不做,即使name是什么时候null!
在MSDN文档说:
为封闭方法或属性指定前置条件协定.
但是如果条件不满足则没有指定任何内容!
我还注意到还有其他 Contract.Requires重载会抛出异常,显示消息......但是接下来是什么Contract.Requires(Boolean)?
EDIT下面的答案强调必须安装一个插件才能充分发挥ContractAPI的作用,那么那些希望他们的代码在不同平台上表现相同的Mono用户呢?
我想在我最新的C#应用程序中通过契约尝试一点设计,并希望语法类似于:
public string Foo()
{
set {
Assert.IsNotNull(value);
Assert.IsTrue(value.Contains("bar"));
_foo = value;
}
}
Run Code Online (Sandbox Code Playgroud)
我知道我可以从单元测试框架中获取这样的静态方法,但是我想知道这样的东西是否已经内置于该语言中,或者是否已经存在某种类型的框架.我可以编写自己的Assert函数,只是不想重新发明轮子.
你可能会觉得这个问题是像这样的问题在计算器上问早.但我试图以不同的方式看待事物.
在TDD中,我们编写包含不同条件,标准,验证码的测试.如果一个班级通过了所有这些测试,我们很高兴.这是一种确保班级实际上做了它应该做的事情而不是别的事情的方法.
如果你按照Bertrand Meyers的书中逐字逐句地介绍面向对象的软件构建,那么这个类本身就有内部和外部的契约,所以它只能做它应该做的事情,而不是别的.不需要进行外部测试,因为确保合同的代码是类的一部分.
快速举例说明事情
TDD
创建测试以确保在所有情况下的值范围为(0-100)
创建一个包含传递测试的方法的类.
DBC
- 创建一个类,为该成员创建一个合同
var范围从(0-100),设置合同违约合同,定义一个方法.
我个人喜欢DBC方法.
有没有理由说纯DBC不那么受欢迎?它是语言或工具还是敏捷,还是我喜欢让代码对自己负责?
如果你认为我思考不对,我会更愿意学习.