是否可以将逻辑放入异常中
本文关键字:异常 是否 | 更新日期: 2023-09-27 17:51:17
我广泛地使用异常,我经常面临在哪里为一个非常特定的异常放置逻辑的困境。
为了说明这一点,假设我已经实现了自己的XML解析器,它接受一个文件路径,打开文件并解析它。现在,在出现解析错误的情况下,我想抛出一个异常,该异常指定文件中不正确的XML的位置。这是通过输出包含
的消息来完成的- 文件名
- 行号
- 最近的字符串内容
一个简化的例子:
void parseXmlFile(string filePath)
{
// …
int line = currentLine();
string surroundingText = StringHelper.getSurroundingText(filePath, offset);
throw new SpecificXmlParseError(filePath, line, surroundingText);
}
但是随着项目的发展,我需要多次重用异常。每次我都被迫重新计算相同的变量,这违反了DRY规则。因此,我想知道是否可以将计算逻辑放入异常中,并仅为其提供计算消息数据所需的参数。它可以像这样:
class SpecificXmlParseError
{
void SpecificXmlParseError(filePath, offset) : base(ComputeMessage(filePath, offset))
{}
static string ComputeMessage(filePath, offset)
{
int line = computeLineBasedOnOffset(filePath, offset);
string surroundingText = StringHelper.getSurroundingText(filePath, offset);
string exceptionMessage = putTogetherMessage(surroundingText);
return exceptionMessage;
}
// ...
}
这里的风险是计算逻辑可能抛出另一个异常。但这有什么特别的原因吗?我能想到的唯一不好的事情是,它会隐藏原始异常(以及真正的原因),不让任何记录器捕捉到它们。但另一方面,在第一种情况下也会发生同样的事情,在异常之前计算数据。还有什么我忘了的问题吗?一个中间的解决方案是编写helper类,它将计算字符串消息。这是迄今为止我想到的最优雅的解决方案,但在这种情况下,它也感觉太过了,并且违反了KISS(毕竟我只想抛出一个异常!)。
有一个双赢的解决方案吗?这些解决方案的优缺点是什么?
这里的风险是计算逻辑可能抛出另一个例外。但这有什么特别的原因吗?
因为异常驱动的代码可能过于复杂,难以理解,因此维护成本很高。
但是在这种情况下(出于错误处理的目的),我认为它一点也不坏。
我认为您需要做的第一件事是将异常记录到日志文件或标准错误流中。那么你就可以确定问题的根源没有消失。这样,即使异常处理代码失败,您仍然有机会进行调查。
如果你的软件是关键任务,那么我会确保错误报告代码没有bug——例如,我会用大量的单元测试来覆盖它。
这里的风险是计算逻辑可能抛出另一个异常。但这有什么特别的原因吗?我认为抛出另一个异常是任何异常处理的事实,除非你只是停止所有的执行。这取决于你想做什么。异常处理作为一种范例有其风险,但您不能完全消除它们。我不认为你的选择会让风险更大。你问题的这一部分我不一定完全理解。
对于DRY,如果您最终在处理中使用相同的逻辑,则建议创建helper类来处理错误。一个首要的设计原则是"选择你的战斗",也就是取决于你认为什么是重要的。DRY经常与KISS相冲突,但并非总是如此。它们是经验法则。设计是不确定的,是一个邪恶的问题(一旦你决定解决部分问题,你就改变了问题)。不要努力让一切都是双赢的。力争可接受。
异常是检测错误并最终指定如何处理它们的逻辑的一种方法。如果逻辑变得复杂或难以维护,那么为它创建专门的(高度内聚的)类。在XML解析错误的情况下,它并没有那么复杂(您只是输出对用户帮助修复XML中的错误有用的信息)。我认为Grzegorz的回答很好地总结了这一部分,他说只要记录它。
在《容错软件模式》一书中的错误处理程序(30)模式中,Robert Hanmer说:"在特殊的处理块中分离错误处理代码,以便于维护和促进将来添加新的处理程序。"这本书有很多关于容错软件模式的建议。报告有关XML错误的信息(文件名、行号、周围文本)的示例恰好是同一本书中Fault Observer (10)模式的一个示例。用户是这类故障的"感兴趣的观察者";这种模式中的观察者不必是系统的内部部分。
转换异常是一个模式,在有层的地方很有用。它类似于汉默的升级(9)模式。
您的应用程序无法真正恢复XML解析错误。有些方法帮助用户尝试通过猜测来修复它们。但是对于您的XML示例来说,这可能有些过分了(不确定它对您的问题有多重要)。如果您有一个用于输入的XSD,您可以获得相当好的验证和有用的错误消息(但我从未编写过它-只是在Eclipse或VisualStudio等ide中使用它)。