到目前为止,我已经做了一年的专业软件工程师,并获得了计算机科学学位。我知道c++和C中的断言有一段时间了,但直到最近才知道它们存在于c#和。net中。

我们的生产代码不包含任何断言,我的问题是这个…

我应该开始在我们的生产代码中使用断言吗?如果可以,什么时候使用它最合适?这样做会更有意义吗

Debug.Assert(val != null, "message");

or

if ( val == null )
    throw new exception("message");

当前回答

使用断言检查开发人员的假设,使用异常检查环境的假设。

其他回答

将Debug.Assert()放在代码中任何需要进行完整性检查以确保不变量的地方。当编译Release版本时(即没有DEBUG编译器常量),对DEBUG . assert()的调用将被删除,因此它们不会影响性能。

在调用Debug.Assert()之前仍然应该抛出异常。断言只是确保在开发过程中一切都如预期的那样。

就其价值而言……我发现我的公共方法倾向于使用if () {throw;}模式,以确保方法被正确调用。我的私有方法倾向于使用Debug.Assert()。

The idea is that with my private methods, I'm the one under control, so if I start calling one of my own private methods with parameters that are incorrect, then I've broken my own assumption somewhere--I should have never gotten into that state. In production, these private asserts should ideally be unnecessary work since I am supposed to be keeping my internal state valid and consistent. Contrast with parameters given to public methods, which could be called by anyone at runtime: I still need to enforce parameter constraints there by throwing exceptions.

此外,如果某些东西在运行时不起作用(网络错误、数据访问错误、从第三方服务检索的坏数据等),我的私有方法仍然可以抛出异常。我的断言只是为了确保我没有破坏我自己关于对象状态的内部假设。

在我的书里几乎从来没有。 在绝大多数情况下,如果你想检查一切是否正常,那么就扔掉。

我不喜欢的是,它使调试构建在功能上与发布构建不同。如果调试断言失败,但功能在发布中工作,那么这有什么意义呢?如果断言者早已离开公司,没有人知道这部分代码,那就更好了。然后你就得花点时间去探索这个问题,看看它是不是真的是个问题。如果这是一个问题,那为什么那个人不第一时间扔呢?

对我来说,这建议使用调试。声称你把问题推给别人,自己解决问题。如果某件事应该是这样,但事实并非如此,那就扔掉。

我猜可能有一些性能关键的场景,你想要优化你的断言,它们在那里很有用,但是我还没有遇到这样的场景。

我想再添加四种情况,其中Debug。断言可以是正确的选择。

1)我在这里没有看到提到的是assert在自动化测试期间可以提供的额外概念覆盖。举个简单的例子:

当作者认为他们已经扩展了代码的范围以处理额外的场景,并修改了一些高级调用者时,理想情况下(!)他们将编写单元测试来覆盖这种新情况。那么,完全集成的代码可能会表现得很好。

然而,实际上已经引入了一个微妙的缺陷,但在测试结果中没有发现。在这种情况下,被调用者变得不确定,只提供预期的结果。或者,它产生了一个未被注意到的舍入误差。或者造成的错误在其他地方被抵消。或者不仅授予所请求的访问权限,还授予不应该授予的其他特权。等。

此时,被调用者中包含的Debug.Assert()语句加上单元测试驱动的新用例(或边缘用例)可以在测试期间提供宝贵的通知,即原始作者的假设已经失效,并且在没有额外审查的情况下不应该发布代码。断言与单元测试是完美的合作伙伴。

2)此外,有些测试写起来很简单,但成本很高,而且在初始假设下是不必要的。例如:

如果一个对象只能从某个安全的入口点访问,是否应该从每个对象方法对网络权限数据库进行额外查询,以确保调用者具有权限?当然不是。也许理想的解决方案包括缓存或其他一些功能扩展,但设计并不需要这样做。当对象被附加到不安全的入口点时,Debug.Assert()将立即显示。

3)其次,在某些情况下,当以发布模式部署时,您的产品可能对其全部或部分操作没有有用的诊断交互。例如:

Suppose it is an embedded real-time device. Throwing exceptions and restarting when it encounters a malformed packet is counter-productive. Instead the device may benefit from best-effort operation, even to the point of rendering noise in its output. It also may not have a human interface, logging device, or even be physically accessible by human at all when deployed in release mode, and awareness of errors is best provided by assessing the same output. In this case, liberal Assertions and thorough pre-release testing are more valuable than exceptions.

4)最后,有些测试是不必要的,只是因为被呼叫方被认为是非常可靠的。在大多数情况下,代码的可重用性越高,在使其可靠方面投入的精力就越多。因此,对于来自调用方的意外参数,通常使用Exception,而对于来自被调用方的意外结果,则使用Assert。例如:

If a core String.Find operation states it will return a -1 when the search criteria is not found, you may be able to safely perform one operation rather than three. However, if it actually returned -2, you may have no reasonable course of action. It would be unhelpful to replace the simpler calculation with one that tests separately for a -1 value, and unreasonable in most release environments to litter your code with tests ensuring core libraries are operating as expected. In this case Asserts are ideal.

摘自《实用程序员:从熟练工到高手》

Leave Assertions Turned On There is a common misunderstanding about assertions, promulgated by the people who write compilers and language environments. It goes something like this: Assertions add some overhead to code. Because they check for things that should never happen, they'll get triggered only by a bug in the code. Once the code has been tested and shipped, they are no longer needed, and should be turned off to make the code run faster. Assertions are a debugging facility. There are two patently wrong assumptions here. First, they assume that testing finds all the bugs. In reality, for any complex program you are unlikely to test even a miniscule percentage of the permutations your code will be put through (see Ruthless Testing). Second, the optimists are forgetting that your program runs in a dangerous world. During testing, rats probably won't gnaw through a communications cable, someone playing a game won't exhaust memory, and log files won't fill the hard drive. These things might happen when your program runs in a production environment. Your first line of defense is checking for any possible error, and your second is using assertions to try to detect those you've missed. Turning off assertions when you deliver a program to production is like crossing a high wire without a net because you once made it across in practice. There's dramatic value, but it's hard to get life insurance. Even if you do have performance issues, turn off only those assertions that really hit you.