this question中的代码让我想到了
assert(value>0); //Precondition
if (value>0)
{
//Doit
}
我从不写if语句。断言就足够/您可以做的所有事情。 “早点崩溃,经常崩溃”
我不认为您通过更正无效输入值或跳过代码使应用程序更加健壮:
assert(value >= 0 ); //Precondition
assert(value <= 90); //Precondition
if(value < 0) //Just in case
value = 0;
if (value > 90) //Just in case
value = 90;
//Doit
这些更正是基于您对外部世界的假设。 只有调用者知道你的函数的“有效输入值”是什么,并且他必须在调用你的函数之前检查它的有效性。
用CodeComplete来解释: “当我们不完全依赖断言时,真实世界的程序变得太乱了。”
问题:我错了,顽固,愚蠢,太不防守......
答案 0 :(得分:10)
信任Asserts的问题在于它们可能在生产环境中被关闭。引用维基百科文章:
大多数语言都允许断言 全局启用或禁用,以及 有时独立。断言 通常在开发期间启用 在最终测试期间和 在向客户发布时不 检查断言以避免成本 评估断言的同时, 假设断言没有 副作用,仍然产生相同的 结果在正常情况下。下 异常情况,禁用 断言检查可能意味着a 会中止的程序会 继续跑。这有时候 优选的。 Wikipedia
因此,如果您的代码的正确性依赖于Asserts,那么您可能会遇到严重的问题。当然,如果代码在测试期间工作,它应该在生产期间工作...现在进入第二个工作代码的人,只是要解决一个小问题......
答案 1 :(得分:4)
使用断言来验证您控制的输入:私有方法等。
使用if语句验证您无法控制的输入:设计用于用户使用的公共接口,用户输入测试等。
使用内置的断言测试应用程序。然后在没有断言的情况下进行部署。
答案 2 :(得分:3)
在某些情况下,构建发布时会断言断言。您可能无法控制它(否则,您可以使用断言构建),因此最好这样做。
“纠正”输入值的问题在于调用者无法获得他们所期望的内容,这可能会导致程序完全不同的部分出现问题甚至崩溃,从而使调试成为一场噩梦。
我经常在if语句中抛出一个异常,以便在它们被禁用的情况下接管assert的角色
assert(value>0);
if(value<=0) throw new ArgumentOutOfRangeException("value");
//do stuff
答案 3 :(得分:2)
我不同意这句话:
只有来电者知道什么是“有效的 输入值“是为你的功能,和 他必须在他之前检查其有效性 调用你的功能。
来电者可能认为他知道输入值是正确的。只有方法作者知道它如何工作。程序员的最佳目标是让客户陷入“pit of success”。在特定情况下,您应该确定哪种行为更合适。在某些情况下,可以原谅不正确的输入值,在其他情况下,您应该抛出异常\返回错误。
对于Asserts,我会重复其他评论者,断言是代码作者的 debug 时间检查,而不是代码客户端。
答案 4 :(得分:1)
如果我从CS-class中正确记得
前提条件定义函数输出定义的条件。如果使函数处理错误条件,则为这些条件定义函数,并且不需要断言语句。
所以我同意。通常你不需要两者。
正如Rik评论的那样,如果在已发布的代码中删除断言,这可能会导致问题。通常我不会这样做,除非在性能关键的地方。
答案 5 :(得分:1)
不要忘记大多数语言都允许你关闭断言......就个人而言,如果我准备编写测试以防止所有范围的无效输入,我不会打扰首先是断言。
另一方面,如果你没有编写逻辑来处理所有情况(可能是因为尝试继续使用无效输入是不明智的)那么我将使用断言语句并进行“早期失败”方法
答案 6 :(得分:0)
对于仅供您使用的内部功能,仅使用断言。断言将有助于在测试期间捕获错误,但不会妨碍生产中的性能。
使用 if-conditions 检查外部发起的输入。从外部来看,这是您/您的团队控制和测试的代码之外的任何地方。
您可以选择两者。这将是面向外部的功能,其中集成测试将在生产之前完成。
答案 7 :(得分:0)
我应该说我知道断言(这里)在生产代码中消失了。
如果if语句实际纠正了生产代码中的无效输入数据,这意味着断言在测试调试代码期间从未停止过,这意味着您编写的代码从未执行过。
对我而言,这是一种情况:
(引用安德鲁)“防止所有无效输入范围,我首先不打扰这个断言。” - &GT;写一个if-test。
(引用aku)“不正确的输入值可以原谅” - &gt;写一个断言。
我不能站在两个......
答案 8 :(得分:-1)
断言的一个问题是它们可以(并且通常会)从代码中编译出来,所以你需要添加两个墙,以防编译器抛弃它们。