Microsoft 异常处理块 - 这不是过度设计的完美示例吗?
自从 Microsoft 引入应用程序块以来,我一直遇到使用 的人异常处理应用程序块。 我最近自己仔细研究了一下,并将基本功能总结如下(如果您已经知道它的作用,请跳过以下块):
异常处理应用程序块旨在集中并使用以下配置文件进行完全配置关键异常处理任务:
- 记录异常
- 替换异常
- 包装异常
- 传播异常
- 等等
该库通过让您修改 try catch 块来实现此目的,如下所示:
<前><代码>尝试 { // 运行代码。 } 捕获(DataAccessException 前) { bool rethrow = ExceptionPolicy.HandleException(例如,“数据访问策略”); 如果(重新抛出) { 扔; } }基于 app.config 中为策略名称指定的内容(请参阅这里的文档),HandleException将...
- 抛出一个全新的异常(替换原来的异常)
- 将原始异常包装在一个新异常中并抛出该异常
- 吞掉异常(即什么也不做)
- 是否重新抛出原始异常
此外,您还可以将其配置为预先执行更多操作(例如记录异常)。
现在我的问题是:我完全不明白无论异常是被替换、包装、吞没还是重新抛出,使其可配置有什么好处。 根据我的经验,必须在编写代码时做出此决定,因为当您更改异常处理行为时,通常必须更改周围或调用代码。
例如,当您重新配置时,您的代码可能会开始表现不正确,以便在特定点引发的特定异常现在被吞没而不是重新引发(catch 块后面可能有一些代码,当异常发生时不得执行)。 这同样适用于异常处理中所有其他可能的更改(例如替换 -> 重新抛出、吞下 -> 包装)。
所以,对我来说,底线是异常处理块解决了实践中真正不存在的问题。 异常记录和通知位很好,但所有其他东西不都是过度设计的完美示例吗?
Ever since Microsoft has introduced the application blocks, I've been bumping into people who use the Exception Handling Application Block. I've recently had a closer look myself and would summarize the basic functionality as follows (skip the following block if you already know what it does):
The exception handling application block aims to centralize and make fully configurable with config files the following key exception handling tasks:
- Logging an Exception
- Replacing an Exception
- Wrapping an Exception
- Propagating an Exception
- etc.
The library does that by having you modify your try catch blocks as follows:
try { // Run code. } catch(DataAccessException ex) { bool rethrow = ExceptionPolicy.HandleException(ex, "Data Access Policy"); if (rethrow) { throw; } }
Based on what is specified in the app.config for the policy name (see here for docs), HandleException will either ...
- throw a completely new exception (replace the original exception)
- wrap the original exception in a new one and throw that
- swallow the exception (i.e. do nothing)
- have you rethrow the original exception
Additionally you can also configure it to do more stuff beforehand (e.g. log the exception).
Now here's my problem: I completely fail to see how it can be beneficial to make it configurable whether an exception is replaced, wrapped, swallowed or rethrown. In my experience, this decision must be made at the time you write the code because you'll typically have to change the surrounding or calling code when you change the exception handling behavior.
For example, your code will likely start to behave incorrectly when you reconfigure such that a particular exception thrown at a particular point is now swallowed instead of rethrown (there might be code after the catch block that must not be executed when the exception occurs). The same goes for all other possible changes in exception handling (e.g. replace -> rethrow, swallow -> wrap).
So, to me the bottom line is that the exception handling block solves problems that really don't exist in practice. The exception logging and notifying bit is fine, but isn't all the other stuff just a perfect example for overengineering?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
如果您使用异常来控制流,那么您将希望远离基于策略的异常处理。
但是,如果您希望将异常视为不可恢复(后台任务失败、套接字断开连接、文件被删除等),您可能需要可配置的、基于策略的异常处理。
例如,如果您正在开发 API,您可能希望 API 中的每个函数仅抛出标准异常(
ArgumentException
等),以及您自己的库特定异常内部非标准异常的情况(例如MyLibraryException
)。 在这种情况下,重要的是某些东西无法正常工作。 您并没有分解异常并找出问题所在。 您只是承认某些事情出了问题,并且您现在应该做某些事情。某些东西应该是可配置的,因为你做什么并不重要。 向用户显示消息框? 模态还是非模态? 记录异常? 您想如何记录异常? 调用日志 Web 服务? 附加到日志文件? 写入 Windows 事件日志? 在数据库中插入一个条目? 将条目插入两个数据库? 这对你的应用程序的其余部分并不重要。 如何处理异常的选择与应用程序的其余部分完全正交。
(顺便说一句,这不是我处理基于可配置策略的异常处理的方式。我更倾向于 AOP 风格,例如在容器中注册异常记录器拦截器。)
If you use exceptions for control flow, then you would want to stay away from policy-based exception handling.
But in the case of exceptions which you want to treat as non-recoverable (a background task failed, the socket was disconnected, the file was deleted, etc.), you may want to have configurable, policy-based exception handling.
For example, if you are developing an API, you may want to have every function in your API throw only the standard exceptions (
ArgumentException
, etc.), as well as your own library-specific exception in the case of an inner non-standard exception (e.g. aMyLibraryException
). In this type of case, all that matters is that something did not work correctly. You are not picking apart the exception and figuring out what went wrong. You are simply acknowledging the fact that something went wrong, and that you are supposed to do something now.That something should be configurable, because it doesn't really matter what you do. Display a Message Box to the user? Modal or non-modal? Log the exception? How do you want to log the exception? Call a logging web service? Append to a log file? Write to the Windows Event Log? Insert an entry into the database? Insert an entry into two databases? It doesn't really matter to the rest of your application. The choice of how to handle an exception is completely orthogonal to the rest of the application.
(As an aside, this is not how I would approach configurable policy-based exception-handling. I would tends more towards an AOP style, such as registering an exception-logger interceptor in the container.)
当我开发没有可恢复状态的函数时,我遇到了这个问题。 我相信这种策略驱动的异常处理实际上是有用的,并确保属于该项目的所有其他开发人员实际上遵守不可恢复异常的标准。
我同意上面的海报,如果您使用基于策略的异常来控制流程,您可能希望远离它们。
I run into this problem when I am developing functions that have no recoverable state. I believe this policy driven exception handling is actually useful and ensures that all the other developers that are part of this project actually adhere to a standard for non-recoverable exceptions.
I agree with the posters above, you may want to stay away from policy based exceptions if you are using them for control flow.
我不得不同意“异常处理块解决了实际中确实不存在的问题”的说法。 自从该模块发布以来,我一直在使用它,但我很少觉得自己通过使用它获得了很多收获。 嗯,也许有点头疼。 :)
在开始之前,我承认我确实喜欢 WCF 服务的异常屏蔽边界功能。 然而,这是最近添加的,不涉及任何编码——只涉及属性和配置,并且不是块通常的销售方式。 这是 Microsoft 在 http://msdn.microsoft.com/en 上显示的方式-us/library/cc309250.aspx
在我看来,上面是流量控制。
当您将流量控制方面与上面的代码结合起来时,您绝对不会让错误的代码看起来错误。 (不必介意 if(重新抛出)构造不提供太多抽象。)这可能会使不熟悉策略定义的开发人员的维护变得更加困难。 如果配置文件中的 postHandlingAction 发生更改(可能会在某个时刻发生),您可能会发现应用程序以从未测试过的意外方式运行。
如果该块不处理流量控制而只是允许您将处理程序链接在一起,也许我不会觉得它令人反感。
但也许不是。 我实际上不记得曾经被要求:
我并不是说这不会发生(我确信有人有故事!); 我只是觉得异常处理应用程序块使程序更难以理解和维护,这通常超过了该块提供的功能。
I have to agree with the statement that "the exception handling block solves problems that really don't exist in practice." I've used the block since its release and I rarely feel like I'm actually gaining much by using it. Well, perhaps a bit of a headache. :)
Before starting, I will admit that I do like the Exception Shielding at WCF Service Boundaries functionality. However, that was added fairly recently, involves no coding -- only attributes and configuration, and is not how the block is usually sold. This is how Microsoft shows it at http://msdn.microsoft.com/en-us/library/cc309250.aspx
To my eyes the above is flow control.
When you combine the flow control aspect with the code above you are definitely not making wrong code look wrong. (Never mind that the if (rethrow) construct does not offer very much abstraction.) This can make maintenance more difficult for developers unfamiliar with the policy definitions. If the
postHandlingAction
in the configuration file is changed (it will probably happen at some point) you will probably find the application behaving in unexpected ways that have never been tested.Perhaps I wouldn't find it as objectionable if the block did not handle flow control but simply allowed you to chain handlers together.
But perhaps not. I don't actually recall ever being asked to:
I'm not saying that it doesn't happen (I'm sure someone has a story!); I just feel that the Exception Handling Application Block makes programs harder to understand and maintain and this usually outweighs the functionality provided by the block.
我认为这根本就不是工程问题。 实际上。 事实上,异常可以通过中央处理程序传递,这在我的工作中是一件好事。 我有一些开发人员会吃掉所有异常 - 处理或不处理,这样它就不会冒泡到顶部并在最终用户面前放置一些令人震惊的东西,或者在未捕获时严重搞乱服务/守护进程。
现在,通过该策略,我们可以随时开始日志记录,而无需重新启动或在整个应用程序中不必要地散布日志记录逻辑。 现在我们可以在不使应用程序离线的情况下观察异常情况等。
智能编程如果你问我......
I don't think this is over engineering at all. in fact. the fact that exceptions can pass through a central handler has been a good thing in my line of work. i have had developers who would eat every exception - handled or not so that it would not bubble to the top and put something alarming in front of the end user or seriously mess up a service/daemon when uncaught.
now with the policy we can start logging at any time without having to restart or needlessly sprinkle logging logic throughout the app. now we can watch exceptions and the like all without taking the app offline.
smart programming if you ask me...
很简单:如果您希望在发布代码中与调试代码中进行不同的异常处理,那么它会很有用。
Quite simply: if you want different exception handling in your release code than in your debug code, then it would be useful.
在我看来,使用异常处理块的一个真正价值始于 catch 块中的一行代码:
bool rethrow = ExceptionPolicy.HandleException(ex, "Data Access Policy");
一行代码——你能有多简单? 在一行代码后面,配置的策略使得对策略的分配/更新变得容易,而无需重新编译源代码。
正如前面提到的,异常策略实际上可以执行许多操作——无论策略中定义什么。 将复杂性隐藏在 catch 块中所示的一行代码后面,才是我看到真正价值的地方。
我想说的是复杂,但不是过度设计。 所以我的想法是,当您需要通过灵活地轻松更改配置来更改处理/记录异常的方式,并且仍然具有相同的一行源代码时,在维护期间将会看到巨大的红利。
In my opinion, one real value of using the Exception Handling block begins with the one line of code in your catch block:
bool rethrow = ExceptionPolicy.HandleException(ex, "Data Access Policy");
One line of code -- how simple can you get? Behind the one line of code, the policy, as it is configured, makes assignment/updates to a policy are easily carried out, all without having to recompile source code.
As was mentioned, the exception policy can actually perform many actions -- whatever is defined in your policy. Hiding complexity behind the one line of code as shown within the catch block, is where I see real value.
I would say complex, but not overengineered. So my thoughts are that big dividends will be seen during maintenance when you're needing to change the way you're handling/logging exceptions by having the flexibility to change configuration easily, and still have the same one line of source code.