Microsoft 异常处理块 - 这不是过度设计的完美示例吗?
-
03-07-2019 - |
题
自从微软推出应用程序块以来,我一直遇到使用该应用程序块的人 异常处理应用程序块. 。我最近自己仔细研究了一下,并将基本功能总结如下(如果您已经知道它的作用,请跳过以下块):
异常处理应用程序块旨在集中并使用以下配置文件进行完全配置 关键异常处理任务:
- 记录异常
- 替换异常
- 包装异常
- 传播异常
- ETC。
该库通过让您修改 try catch 块来实现此目的,如下所示:
try { // Run code. } catch(DataAccessException ex) { bool rethrow = ExceptionPolicy.HandleException(ex, "Data Access Policy"); if (rethrow) { throw; } }
基于 app.config 中指定的策略名称(请参阅此处的文档), HandleException 将...
- 抛出一个全新的异常(替换原来的异常)
- 将原始异常包装在一个新异常中并抛出该异常
- 吞下异常(即没做什么)
- 你重新抛出原来的异常了吗
此外,您还可以将其配置为预先执行更多操作(例如记录异常)。
现在这是我的问题:我完全不明白无论异常是被替换、包装、吞没还是重新抛出,使其可配置有什么好处。根据我的经验,必须在编写代码时做出此决定,因为当您更改异常处理行为时,通常必须更改周围或调用代码。
例如,当您重新配置时,您的代码可能会开始表现不正确,以便在特定点引发的特定异常现在被吞没而不是重新引发(catch 块后面可能有代码,当异常发生时不得执行)。这同样适用于异常处理中所有其他可能的更改(例如替换 -> 重新抛出,吞下 -> 包裹)。
所以,对我来说,底线是异常处理块解决了实践中真正不存在的问题。异常记录和通知位很好,但所有其他东西不都是过度设计的完美示例吗?
解决方案
如果您使用异常来控制流,那么您将希望远离基于策略的异常处理。
但是,如果您希望将异常视为不可恢复(后台任务失败、套接字断开连接、文件被删除等),您可能需要可配置的、基于策略的异常处理。
例如,如果您正在开发 API,您可能希望 API 中的每个函数仅抛出标准异常 (ArgumentException
, 等),以及在内部非标准异常(例如,A MyLibraryException
)。在这种情况下,重要的是某些东西无法正常工作。您并没有分解异常并找出问题所在。你只是承认这样一个事实 一些事情出了问题,你应该做的 一些现在的事情。
那 一些事情应该是可配置的,因为你做什么并不重要。向用户显示消息框?模态还是非模态?记录异常?您想如何记录异常?调用日志 Web 服务?附加到日志文件?写入 Windows 事件日志?在数据库中插入一个条目?将条目插入两个数据库?这对你的应用程序的其余部分并不重要。如何处理异常的选择与应用程序的其余部分完全正交。
(顺便说一句,这不是我处理基于可配置策略的异常处理的方式。我更倾向于 AOP 风格,例如在容器中注册异常记录器拦截器。)
其他提示
当我开发没有可恢复状态的函数时,我遇到了这个问题。我相信这种策略驱动的异常处理实际上是有用的,并确保属于该项目的所有其他开发人员实际上遵守不可恢复异常的标准。
我同意上面的海报,如果您使用基于策略的异常来控制流程,您可能希望远离它们。
我必须同意“异常处理块解决了实际上不存在的问题。“自该区块发布以来,我一直在使用它,我很少觉得自己通过使用它实际上获得了很多收益。嗯,也许有点头疼。:)
在开始之前,我承认我确实喜欢 WCF服务边界的异常屏蔽 功能。然而,这是最近添加的,不涉及任何编码——只涉及属性和配置,并且不是块通常的销售方式。这就是微软展示它的方式 http://msdn.microsoft.com/en-us/library/cc309250.aspx
在我看来,上面是流量控制。
try
{
// Run code.
}
catch(DataAccessException ex)
{
bool rethrow = ExceptionPolicy.HandleException(ex, "Data Access Policy");
if (rethrow)
{
throw;
}
}
当您将流量控制方面与上面的代码结合起来时,您绝对不会 让错误的代码看起来错误. 。(不必介意 if(重新抛出)构造不提供太多抽象。)这可能会使不熟悉策略定义的开发人员的维护变得更加困难。如果 postHandlingAction
配置文件中的内容发生更改(可能会在某个时刻发生),您可能会发现应用程序以从未测试过的意外方式运行。
如果该块不处理流量控制而只是允许您将处理程序链接在一起,也许我不会觉得它令人反感。
但也许不是。我实际上不记得曾经被要求:
- 在处理异常时添加一项新功能(例如除了记录到事件日志之外,还可以发送电子邮件。实际上,如果您已经自己记录异常,则日志记录块可以自行执行此操作。:) )
- 更改整个“策略”中的异常处理行为(吞掉、重新抛出或抛出新的异常)。
我并不是说这不会发生(我确信有人有故事!);我只是觉得异常处理应用程序块使程序更难理解和维护,这通常超过了该块提供的功能。
我认为这根本就不是工程问题。实际上。事实上,异常可以通过中央处理程序传递,这在我的工作中是一件好事。我有一些开发人员会吃掉所有异常 - 处理或不处理,这样它就不会冒泡到顶部并在最终用户面前放置一些令人震惊的东西,或者在未捕获时严重搞乱服务/守护进程。
现在,通过该策略,我们可以随时开始日志记录,而无需重新启动或在整个应用程序中不必要地散布日志记录逻辑。现在我们可以在不使应用程序离线的情况下观察异常情况等。
智能编程如果你问我......
很简单:如果您希望在发布代码中与调试代码中进行不同的异常处理,那么它将很有用。
在我看来,使用异常处理块的真正价值始于 catch 块中的一行代码:
bool rethrow = ExceptionPolicy.HandleException(例如,“数据访问策略”);
一行代码——你能有多简单?在一行代码后面,配置的策略使得对策略的分配/更新变得容易,而无需重新编译源代码。
正如前面提到的,异常策略实际上可以执行许多操作——无论策略中定义什么。将复杂性隐藏在 catch 块中所示的一行代码后面,才是我看到真正价值的地方。
我想说的是复杂,但不是过度设计。所以我的想法是,当您需要通过灵活地轻松更改配置来更改处理/记录异常的方式,并且仍然具有相同的一行源代码时,在维护期间将会看到巨大的红利。