将逻辑置于异常中是否可以?

时间:2014-03-22 19:21:00

标签: c# java design-patterns solid-principles design-principles

我广泛使用异常,而且我经常面临在哪里为特定异常设置逻辑的困境。

为了说明,我们说我已经实现了自己的XML解析器,它采用文件路径,打开文件并解析它。现在,在解析错误的情况下,我想抛出一个异常,它指定文件中不正确的XML的位置。这是通过输出包含

的消息来完成的
  1. 文件名
  2. 行号
  3. 最近的字符串内容
  4. 到目前为止,我一直试图通过仅使用标量来提供异常,因为它们可能会立即用于消息中。这已经成为我的规则:在异常中尽可能少的逻辑。遵循该规则,异常中使用的变量的任何计算都位于该异常之外。

    简化示例:

    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;
        }
        // ...
    }
    

    这里的风险是计算逻辑可以抛出另一个异常。但这有什么不好的具体原因吗?我能想到的唯一不好的事情是它会隐藏原始异常(和真正的原因)来捕获它们的任何记录器。但另一方面,在第一种情况下会发生同样的事情,即在异常之前计算数据。那么我还有一些额外的担忧吗?

    中间解决方案是编写辅助类,它将计算字符串消息。这是我到目前为止提出的最优雅的解决方案,但在这种情况下也感觉很像并且违反了KISS(毕竟我只想抛出异常!)。

    这是一个双赢的解决方案吗?这些解决方案的优缺点是什么?

2 个答案:

答案 0 :(得分:0)

  

这里的风险是计算逻辑可以抛出另一个   例外。但这有什么特别的原因可以解决这个问题吗?

因为异常驱动的代码可能过于复杂且难以理解,因此维护起来很昂贵。

但在这种情况下(出于错误处理的目的),我认为它一点也不差。

我认为您需要做的第一件事是记录日志文件或标准错误流的异常。然后你确定问题的原因不会丢失。然后,即使异常处理代码失败,您仍有机会进行调查。

如果您的软件是关键任务,那么我会确保错误报告代码没有错误 - 例如,我会用大量的单元测试来覆盖它。

答案 1 :(得分:0)

  

这里的风险是计算逻辑可以抛出另一个异常。但这有什么特别的原因可以解决这个问题吗?

我认为抛出另一个异常是任何异常处理的事实,除非你只是停止所有执行。这取决于你想做什么。异常处理有其作为范例的风险,但您无法完全消除它们。我不认为你的替代方案会让风险变得更糟。我不确定我完全理解你的这部分问题。

至于DRY,它建议创建帮助程序类来处理错误,如果你在处理中最终得到相同的逻辑。总体设计原则"pick your battles" a.k.a.取决于您重视的重要性。 DRY经常与KISS发生冲突,但并非总是如此。它们是经验法则。设计是非确定性的并且是一个邪恶的问题(一旦你决定解决部分问题,你就已经改​​变了问题)。不要努力让一切双赢。争取可接受的

异常是检测错误的一种方法,并最终指定了如何处理它们的逻辑。如果该逻辑变得复杂或难以维护,那么为它创建专门的(高度内聚的)类。在您解决XML解析错误的情况下,它并不是那么复杂(您只是输出对用户有用的信息来帮助修复XML中的错误)。我认为Grzegorz' answer总结一下,只要记录就可以了。

在他的书Patterns for Fault Tolerant Software中的错误处理程序(30)模式中,Robert Hanmer说,"在特殊处理块中分离错误处理代码,以便于维护和促进新的处理程序将在未来添加。"本书有很多关于容错软件模式的好建议。

您报告有关XML错误的信息(文件名,行号,周围文本)的示例正是同一本书中 Fault Observer(10)模式的一个示例。用户是感兴趣的观察者"这种过错;这种模式的观察者不必是系统的内部部分。

Convert exceptions是一种在有图层的情况下非常有用的模式。它类似于Hanmer的 Escalation(9)模式。

您的应用程序无法真正恢复XML分析错误。 Some approaches help the user try to fix them by guessing。但这对您的XML示例来说可能有点过分(不确定它对您的问题有多重要)。如果您有输入的XSD,您可以获得非常好的验证和有用的错误消息(但我从未对其进行编码 - 只是在Eclipse或VisualStudio等IDE中使用它。)