到目前为止,我已经做了一年的专业软件工程师,并获得了计算机科学学位。我知道c++和C中的断言有一段时间了,但直到最近才知道它们存在于c#和。net中。
我们的生产代码不包含任何断言,我的问题是这个…
我应该开始在我们的生产代码中使用断言吗?如果可以,什么时候使用它最合适?这样做会更有意义吗
Debug.Assert(val != null, "message");
or
if ( val == null )
throw new exception("message");
到目前为止,我已经做了一年的专业软件工程师,并获得了计算机科学学位。我知道c++和C中的断言有一段时间了,但直到最近才知道它们存在于c#和。net中。
我们的生产代码不包含任何断言,我的问题是这个…
我应该开始在我们的生产代码中使用断言吗?如果可以,什么时候使用它最合适?这样做会更有意义吗
Debug.Assert(val != null, "message");
or
if ( val == null )
throw new exception("message");
当前回答
根据设计标准,你应该
坚持每一个假设。平均每五行就有一个断言。
using System.Diagnostics;
object GetObject()
{...}
object someObject = GetObject();
Debug.Assert(someObject != null);
作为一个免责声明,我应该提到我还没有发现实现这个IRL是实际的。但这是他们的标准。
其他回答
将Debug.Assert()放在代码中任何需要进行完整性检查以确保不变量的地方。当编译Release版本时(即没有DEBUG编译器常量),对DEBUG . assert()的调用将被删除,因此它们不会影响性能。
在调用Debug.Assert()之前仍然应该抛出异常。断言只是确保在开发过程中一切都如预期的那样。
我不知道它在c#和。net中是怎样的,但在C中assert()只在使用- ddebug编译时工作-如果没有编译,最终用户将永远不会看到assert()。仅供开发人员使用。我经常使用它,它有时更容易跟踪错误。
我不会在产品代码中使用它们。抛出异常,捕获和记录。
在asp.net中也需要小心,因为断言可以显示在控制台上并冻结请求。
John Robbins在《调试Microsoft . net 2.0应用程序》一书中有一大节是关于断言的。他的主要观点是:
Assert liberally. You can never have too many assertions. Assertions don't replace exceptions. Exceptions cover the things your code demands; assertions cover the things it assumes. A well-written assertion can tell you not just what happened and where (like an exception), but why. An exception message can often be cryptic, requiring you to work backwards through the code to recreate the context that caused the error. An assertion can preserve the program's state at the time the error occurred. Assertions double as documentation, telling other developers what implied assumptions your code depends on. The dialog that appears when an assertion fails lets you attach a debugger to the process, so you can poke around the stack as if you had put a breakpoint there.
PS:如果你喜欢《代码完成》,我推荐你继续阅读这本书。我买这本书是为了学习如何使用WinDBG和转储文件,但前半部分包含了一些帮助避免bug的技巧。
我想再添加四种情况,其中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.