Exception 即使不会造成伤害,代码是否应该防止逻辑无效的调用?

Exception 即使不会造成伤害,代码是否应该防止逻辑无效的调用?,exception,error-handling,Exception,Error Handling,这个问题一直困扰着我一段时间了 让我们设想一个表示资源的类,为了能够使用该资源,需要首先对其调用“Open”方法,否则将引发InvalidOperationException 我的代码是否应该检查是否有人试图打开一个已经打开的资源,或者关闭一个已经关闭的资源 即使不会造成伤害,代码是否应该防止逻辑无效的调用 我认为用这种方式编程将有助于在另一方面编写更好的代码,但我觉得我可能承担了太多的责任,影响了可重用性 你们觉得怎么样 编辑: 我不认为这可以被称为防御编程,因为它也不会让可能的坏用途溜走,并

这个问题一直困扰着我一段时间了

让我们设想一个表示资源的类,为了能够使用该资源,需要首先对其调用“Open”方法,否则将引发InvalidOperationException

我的代码是否应该检查是否有人试图打开一个已经打开的资源,或者关闭一个已经关闭的资源

即使不会造成伤害,代码是否应该防止逻辑无效的调用

我认为用这种方式编程将有助于在另一方面编写更好的代码,但我觉得我可能承担了太多的责任,影响了可重用性

你们觉得怎么样

编辑:

我不认为这可以被称为防御编程,因为它也不会让可能的坏用途溜走,并且会抛出另一个InvalidoOperationException

这就是所谓的。这是一个很好的编程实践,因为您可以确保应用程序不会因错误行为而崩溃

在调用另一个方法之前应该先调用某个方法,这不是一个好的编程实践。它增加了很多复杂性,由类本身更好地处理


这就是所谓的。维基百科的这篇文章说,如果这是一种不好的做法,它取决于上下文,但如果处理不当,它不应该崩溃。有时有必要抛出一个异常来澄清问题。

如果您的示例确实如此,那么开放功能可能应该由类的构造函数调用

如果考虑C++的IOSSTATH库(它被广泛使用并被认为是一个很好的例子),你可以调用流类上的任何操作,不管它是打开的还是不打开的。如果操作无法执行,被调用的函数将简单地返回某种类型的故障指示器。当然,为了做到这一点,函数必须测试流状态

您不能允许您的程序以静默方式接受任何旧的输入作为参数。例如,这将是strlen()的一个失败的实现


由于它在不引起麻烦的情况下输入错误,因此它应该抛出异常或使用assert(),这取决于您的确切开发理念。

在计算代码中应包含多少安全检查以实现组织的最佳成本/效益比方面,没有什么可以替代品味、才能和经验

一个高质量的API应该是万无一失的,并用适当数量的警告来指导用户


有时,安全预防措施可能会影响性能。性能是编程中最违反直觉的事情之一。只有当性能真正重要时,才小心地进行优化。

这实际上取决于类的实际功能。在某些情况下,无声故障是一个好主意(例如,您希望您的DVD播放机继续工作,如果它打开已打开的DVD托盘,则不显示错误消息),在其他情况下,您需要尽可能多的信息(例如,如果一架飞机试图关闭一扇据报道已经关闭的门,那么一定是出了问题,应该提醒飞行员)


在大多数情况下,当执行逻辑上无效的操作时抛出错误对开发人员很有用,因此实现这些异常取决于谁将使用代码。如果代码在内部用于一个应用程序,那么它并不重要。但是如果它被许多不同的项目或开发人员使用,那么我会研究它。

如果这是代码的一部分对于您要发布到野外的公共SDK,那么公开的API调用应该具有强大的验证。它将帮助您的“用户”(开发人员)并确保您不会被困在支持您从未打算支持的使用上


否则,我不会添加这样的检查。我认为它们会使代码更难阅读,而且这些检查很少经过测试。过去我会添加很多这样的代码,以确保我的代码不会出错。现在我编写单元测试来验证我的代码是否正确。区别是什么?我认为测试更易于维护,更易于阅读可以,而且它们不会使您的生产代码变得混乱。

在打开已打开的文件的情况下,这取决于是否知道请求的效果,例如是否会重置当前读取位置

在关闭已关闭的文件的情况下,可以将其视为请求将文件置于已知状态。代码不必执行任何操作,只需达到所需状态,代码即可返回成功条件。如果需要处理某种类型的文件缓冲,或者可能需要进行链接,则情况并非如此要协调的ed资源,如调制解调器/串行端口或打印机/后台打印程序

退后一步,从预期结果的角度考虑问题,包括任何副作用


我们曾经在一个应用程序菜单上放置了一个“注销”链接,无论您的登录状态如何,都会显示该链接。为什么?因为它只需要一个简单的(而且非常短的)链接方法来处理从登录屏幕返回登录屏幕的操作,并保存大量检查以处理跟踪登录状态的操作,这样“注销”菜单项仅在您登录时显示。

逻辑无效调用应始终在调试模式下报告给用户

在发布模式下编译时,您的代码不应抛出任何不必要的异常或执行任何可能危及整个应用程序的操作。
就我个人而言,我更喜欢使用某种日志文件,记录这种逻辑上无效的调用肯定不会有任何伤害(至少在性能不重要的情况下)

事实上并非如此。当您预期可能被滥用时,您可以使用防御性编程来防止崩溃(这意味着无论何时您与界面另一端的Unknown(ab)用户进行交互)但是OP问open是否应该处理滥用,因为什么都没有发生。我不同意-应该通知用户他的系统有问题
int strlen( const char * s )
{
   if ( s == 0 )
   {
      return 0;     // bad
   }
   else
   {
      // calculate length not shown
   }
}