捕获异常作为预期的程序执行流程控制?

Gra*_*ank 11 .net sql sql-server exception-handling

我总是觉得期望定期抛出异常并将它们用作流逻辑是一件坏事.例外情况应该是,他们应该是" 例外 ".如果你期望并计划一个异常,这似乎表明你的代码应该被重构,至少在.NET中......
但是.最近的一个场景让我停下来.我刚刚在msdn上发布了这个,但是我想对它进行更多的讨论,这是一个完美的地方!

所以,假设你有一个数据库表,其中有几个其他表的外键(在最初提示辩论的情况下,有4个外键指向它).您希望允许用户删除,但仅限于没有外键引用; 你不想级联删除.
我通常只是检查是否有任何引用,如果有,我通知用户而不是删除.在LINQ中编写它是非常容易和轻松的,因为相关表是对象的成员,所以Section.Projects和Section.Categories等等很好用intellisense和所有类型...
但事实是LINQ然后必须潜在地检查所有4个表以查看是否有任何结果行指向该记录,并且命中数据库显然总是相对昂贵的操作.

这个项目的负责人让我把它改成只捕获一个代码为547(外键约束)的SqlException并以这种方式处理它.

我......
抗拒.

但是在这种情况下,吞下与异常相关的开销可能比吞下4个表命中更有效...特别是因为我们必须在每种情况下进行检查,但我们在这种情况下没有例外当没有孩子的时候......
加上数据库真的应该是负责处理参照完整性的人,这是它的工作而且做得很好......
所以他们赢了,我改变了它.

在某种程度上,我觉得我觉得不对.

你们对期望和故意处理异常有什么看法?它看起来比预先检查更有效吗?对于下一个查看代码的开发人员来说,更令人困惑的是它更令人困惑吗?它是否更安全,因为数据库可能知道开发人员可能不会考虑添加检查的新外键约束?或者是关于你认为最佳实践究竟是什么的观点?

lev*_*vik 7

你的领导是绝对正确的.例外不仅适用于蓝月情况下的一次,而且特别适用于除预期结果之外的报告.

在这种情况下,仍会进行外键检查,例外是可以通知您的机制.

你不应该做的是通过毯子捕获声明来捕获和抑制异常.进行细粒度异常处理特别是为什么首先设计异常.


Rob*_*per 4

哇,

首先,您能否稍微提炼一下这个问题,虽然很高兴阅读一个经过深思熟虑和解释的问题,但需要消化的内容相当多。

简短的回答是“是”,但这取决于情况。

  • 我们有一些应用程序,其中大量业务逻辑与 SQL 查询相关(不是我的设计 Gov!)。如果这就是它的结构,管理层可能很难相信它“已经有效”。
  • 在这种情况下,真的有什么大不了的吗?因为穿过电线来回还需要一趟。服务器在意识到它无法继续之前是否做了很多事情(即,如果您的操作发生了一系列事务,那么它是否会在中途失败,浪费时间?)。
  • 首先在 UI 中进行检查是否有意义?对你的申请有帮助吗?如果它提供了更好的用户体验?(即我见过这样的情况,您在向导中逐步执行几个步骤,它启动,然后崩溃,当它拥有在步骤1之后崩溃所需的所有信息时)。
  • 并发是一个问题吗?在提交发生之前,记录是否可能被删除/编辑或发生任何其他事情(如经典的File.Exists嘘声)。

在我看来:

我会两者兼而有之。如果我能够快速失败并提供更好的用户体验,那就太好了。无论如何,任何预期的 SQL(或任何其他)异常都应该被捕获并适当反馈。

我知道有一个共识,即除特殊情况外不应使用异常,但请记住,我们在这里跨越了应用程序边界,不要期待任何事情。就像我说的,这就像File.Exists,没有任何意义,无论如何,在您访问它之前都可以将其删除。