12

这个问题中的代码让我想到

assert(value>0); //Precondition
if (value>0)
{
  //Doit
}

我从不写 if 语句。断言就足够了/你能做的。“早崩溃,经常崩溃”

CodeComplete状态:

  • 断言语句使应用程序正确
  • if-test 使应用程序健壮

我不认为您通过更正无效的输入值或跳过代码使应用程序更健壮:

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的话:“当我们不完全依赖断言时,现实世界的程序会变得过于混乱。”

问题:我是不是错了,固执,愚蠢,太不防备......

4

9 回答 9

10

只信任断言的问题在于它们可能在生产环境中被关闭。引用维基百科的文章:

大多数语言都允许全局启用或禁用断言,有时甚至是独立的。断言通常在开发过程中启用,在最终测试和发布给客户时禁用。不检查断言避免了评估断言的成本,同时假设断言没有副作用,在正常条件下仍然产生相同的结果。在异常情况下,禁用断言检查可能意味着本应中止的程序将继续运行。这有时是可取的。 维基百科

因此,如果您的代码的正确性依赖于 Asserts 的存在,您可能会遇到严重的问题。当然,如果代码在测试期间工作,它应该在生产期间工作......现在输入第二个处理代码并且只是要解决一个小问题的人......

于 2008-09-11T09:58:39.890 回答
4

使用断言来验证您控制的输入:私有方法等。

使用 if 语句来验证您无法控制的输入:为用户使用而设计的公共接口、用户输入测试等。

使用内置的断言测试您的应用程序。然后在没有断言的情况下进行部署。

于 2008-09-11T10:51:35.800 回答
3

在某些情况下,断言在构建发布时被禁用。您可能无法控制这一点(否则,您可以使用断言进行构建),因此这样做可能是个好主意。

“纠正”输入值的问题是调用者不会得到他们期望的结果,这可能导致程序的完全不同部分出现问题甚至崩溃,使调试成为一场噩梦。

我通常在 if 语句中抛出一个异常来接管断言的角色,以防它们被禁用

assert(value>0);
if(value<=0) throw new ArgumentOutOfRangeException("value");
//do stuff
于 2008-09-11T09:59:01.263 回答
2

I would disagree with this statement:

Only the caller knows what "a valid input value" is for your function, and he must check its validity before he calls your function.

Caller might think that he know that input value is correct. Only method author knows how it suppose to work. Programmer's best goal is to make client to fall into "pit of success". You should decide what behavior is more appropriate in given case. In some cases incorrect input values can be forgivable, in other you should throw exception\return error.

As for Asserts, I'd repeat other commenters, assert is a debug time check for code author, not code clients.

于 2008-09-11T10:09:10.100 回答
1

如果我没记错的话

前提条件定义了函数输出的定义条件。如果你让你的函数处理错误条件,你的函数是为这些条件定义的,你不需要断言语句。

所以我同意。通常你不需要两者。

正如 Rik 评论的那样,如果您在已发布的代码中删除断言,这可能会导致问题。通常我不这样做,除非在性能关键的地方。

于 2008-09-11T09:59:31.697 回答
1

Don't forget that most languages allow you to turn off assertions... Personally, if I was prepared to write if tests to protect against all ranges of invalid input, I wouldn't bother with the assertion in the first place.

If, on the other hand you don't write logic to handle all cases (possibly because it's not sensible to try and continue with invalid input) then I would be using the assertion statement and going for the "fail early" approach.

于 2008-09-11T10:06:35.613 回答
0

我应该说我知道断言(此处)在生产代码中消失的事实。

如果 if 语句实际上纠正了生产代码中的无效输入数据,这意味着断言在调试代码测试期间从未发生过,这意味着您编写的代码从未执行过。

对我来说,这是一个 OR 情况:

(引用 Andrew)“防止所有范围的无效输入,我一开始就不会为断言而烦恼。” -> 编写一个 if 测试。

(引用 aku)“可以原谅不正确的输入值”-> 写一个断言。

两个都受不了

于 2008-09-11T10:44:31.543 回答
0

For internal functions, ones that only you will use, use asserts only. The asserts will help catch bugs during your testing, but won't hamper performance in production.

Check inputs that originate externally with if-conditions. By externally, that's anywhere outside the code that you/your team control and test.

Optionally, you can have both. This would be for external facing functions where integration testing is going to be done before production.

于 2008-09-11T10:08:10.773 回答
-1

断言的一个问题是它们可以(并且通常会)从代码中编译出来,因此您需要添加两面墙,以防编译器丢弃它们。

于 2008-09-11T10:00:18.827 回答