@
wysnylc 发出几个异常收藏的文章的链接。我顺便给大家概括一下。
##A
https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/exception-throwing 这是微软的关于如何设计 library ( framework design guideline )的电子书的一个章节。注意看左边子目录里面共有 4 篇关于异常的文章(第一篇是简介)。
注意这是关于如何设计 library 的文章,其中大部分东西可以适用于业务上,例如 test-doer 模式、try-parse 模式;而某些条条框框不能套在业务代码上面,例如 "DO NOT use error codes" 。
当然,关于 library 使用异常还是 go 风格的东西(error codes),还需要深入研究。不过已知的是,java/c#的东西久经检验,不会差。
另外,如果心存疑问的话,可以去 GitHub 上面 clone 一下 CoreFx (.net core 标准库)的代码。我简单的看了少部分,发现:
1. 大部分 throw 代码,抛出的都是 ArgumentException (ArgumentException, ArgumentNullException, ArgumentOutOfRangeException),还有 InvalidOperationException。为什么会这样呢?答案很自然:因为出了问题,问题肯定在 caller 的传参上面,或者在 [当前对象的状态不合适] 上面。正如 C# Docs 所言,InvalidOperationException is used in cases when the failure to invoke a method is caused by reasons other than invalid arguments.
2. 这些异常的抛出都是这样抛出的 if(argument x not satisfy some condition) throw ArguementXXXXXException. 并且每个函数开头几乎都会检查所有参数。(这很自然。记住这样做也是标准做法。)
3. 很少能看见捕获异常的代码。所以不要动不动就捕获异常。总而言之,你的 library 和业务都应几乎不出现 catch。这些东西你都不用关心。想一想 catch 了也没啥用。
4. 小部分捕获异常的代码,几乎捕获的都是 InvalidCastException 之类的. InvalidCastException 是由于失败的转换类型抛出的。这都是在架构里面属于有点底层的东西,可能某些东西设计不当,我也没深究,平时应该不会碰到。
5. 我也看了 EntityFrameworkCore 的代码。发现,也不能说完全不用 catch 吧。EF 的 catch 还涉及到这样的东西:捕获 - 记录(log) - rethrow。如果你有这样做的需求,你可以这样做。
6. 捕获异常的操作还可用于:(节选自 docs of Exception.InnerException )“你可以创建一个新的异常来捕获更早的异常。 处理第二个异常的代码可以利用以前异常中的其他信息来更正确地处理错误。”。 我的评论:EFCore 也有少量这种代码,但是平时会很少有这种应用场景。设计 Library 的时候,如果你想要捕获异常后加点料,也可以加在 Exception.Data 属性。docs of Exception.Data: "to store and retrieve supplementary information relevant to the exception"。
7. 内层的不恰当设计(或者天生的缺陷),会影响外层的代码。这很好理解:如果业务 HelperClass 使用异常来返回错误代码,那么外层的代码也会被迫用这种愚蠢的方式写组织代码。第二,何谓天生的缺陷?我的理解是"互操作"的天生不足。你去调用一个其他语言的东西(例如 c 语言的),这些东西和契合的本来就不如当前语言好。
## B 和 C
这两篇文章能加深对异常处理的理解。
http://www.informit.com/articles/article.aspx?p=433387https://enterprisecraftsmanship.com/posts/error-handling-exception-or-result/## D
https://martinfowler.com/articles/replaceThrowWithNotification.html我直到刚才,才发现,这篇文章是 Martin Fowler 写的!!!!!
它讲了 Validations (验证输入)时应该以 Notification 的方式(类似于一个 Result Class,或许可以将业务的 result class 和这个结合起来)。主要场景大概是处理 http 接口传入的参数。( ModelValidation )