【问题标题】:How can I find out which exceptions a Delphi function might throw?如何找出 Delphi 函数可能抛出的异常?
【发布时间】:2008-09-16 14:00:10
【问题描述】:

有没有一种好方法可以找出在 Delphi 中一个过程/函数可以引发哪些异常(包括它被称为过程/函数)?

在 Java 中,您总是必须声明可以抛出哪些异常,但在 Delphi 中并非如此,这可能会导致未处理的异常。

是否有任何代码分析工具可以检测未处理的异常?

【问题讨论】:

  • 添加一个“为什么”来解决这个问题可能对你有好处。
  • 吉姆是对的。很难提供正确的答案,因为我们不知道您想要实现什么。
  • 如果想要记录这些方法,可能会有某种方法注释

标签: delphi exception-handling


【解决方案1】:

(编辑:现在很明显,该问题提到了设计时检查。)

新答案:

我无法说明是否有任何工具可以为您检查。一方面,Pascal Analyzer 没有。

可以告诉你,然而,在大多数 Delphi 应用程序中,即使有一个工具可以帮你检查,你也不会得到任何结果。

为什么? 因为 TApplication.Run() 中的主消息循环将所有 HandleMessage() 调用包装在一个异常处理块中,该块捕获所有异常类型。因此,在大多数应用程序中,您将拥有大约 99.999% 的代码的隐式/默认异常处理。而且在大多数应用程序中,这种异常处理将大约 100% 发生在您自己的代码中 - 未包装在异常处理中的 0.001% 的代码将是自动生成的代码。

如果有工具可以为您检查,您需要重写 Application.run() 使其不包括异常处理。

(上一个答案: 可以分配 Application.OnException 事件处理程序来捕获其他异常处理程序未处理的所有异常。虽然这是运行时,因此可能不完全是您所追求的(听起来您想在设计时识别它们),但它确实允许您捕获任何未在其他地方处理的异常。结合Jedi Code Library 中的 JCLDebug 等工具,您可以记录堆栈跟踪以找出异常发生的位置和原因,这将允许进一​​步调查并围绕有罪代码添加特定的异常处理或预防。 .)

【讨论】:

    【解决方案2】:

    我的猜测是你试图让 Delphi 表现得像 Java,这不是一个好方法。我建议不要太担心未处理的异常。在最坏的情况下,它们会冒泡到通用 VCL 异常处理程序并导致 Windows 消息对话框。在正常的应用程序中,它们不会停止应用程序。

    编写良好的代码会记录可能引发的不同异常,以便您以有意义的方式处理它们。不建议使用包罗万象的处理程序,因为如果您不知道为什么会引发异常,则实际上无法知道该怎么做。我也强烈推荐 madExcept。

    【讨论】:

    • 我也推荐madExcept。
    【解决方案3】:

    除了对“raise”关键字的扫描之外,Delphi 中没有任何语言结构可以告诉不经意的读者可以从方法中预期哪些异常。

    在运行时,可以在每个方法中添加一个包罗万象的异常处理程序,但这是不可取的,因为它会减慢执行速度。 (而且做起来也很麻烦)。

    向方法添加异常处理块将向其添加一些汇编指令(即使未触发异常),当方法被频繁调用时,这会形成可测量的减速。

    确实存在一些可以帮助您分析运行时异常的库,例如 madExceptJclDebugEurekaLog。这些工具可以记录有关异常的各种详细信息,强烈建议使用其中之一!

    【讨论】:

    • 尝试...除了真的减慢执行速度(如果没有发生异常)吗?
    • @mjn : 是的,但是只有在你应用 try..except 在经常调用的函数和/或大腿循环中时它才会变得明显。
    • 我会推荐 jclDebug 或 madExcept 但不推荐 EurekaLog,因为这会导致问题。
    【解决方案4】:

    简短的回答是没有任何工具可以做到你所说的,即使是扫描 raise 关键字也无法让你到达那里。 EAccessViolationEOutOfMemory 只是可能在任何地方引发的众多异常中的两个。

    关于 Delphi 的一个基本特性是异常是分层的:所有定义的语言异常都源自 Exception,尽管值得注意的是实际上可以引发任何 TObject后代。

    如果您想捕获在特定过程中引发的每个异常,只需将其包装在 try / except 块中,但如前所述 不建议这样做

    // Other code . . . 
    try
      SomeProcedure()
    except  // BAD IDEA!
      ShowMessage('I caught them all!');
    end;
    

    这将捕获所有内容,甚至是引发 TObject 的实例。尽管我认为这很少是最好的做法。通常您希望使用 try / finally 块,然后允许全局异常处理程序(或最后一个 try / except 块)实际处理异常。

    【讨论】:

      【解决方案5】:

      我会第二个(或者是第三个)MadExcept。我已经在几个商业应用程序中成功使用它,没有任何问题。 MadExcept 的好处在于,它会为您生成一份包含完整堆栈跟踪的报告,该报告通常会为您指出错误的正确方向,甚至可以包含屏幕截图,并自动将其通过电子邮件发送给您只需单击鼠标即可从客户端计算机上。

      但是,您不想将它用于所有异常,只是为了捕获您错过的异常。例如,如果您打开一个数据库并且登录失败,您最好自己捕获并处理这个数据库,而不是在您的应用程序发生消息中向用户提供 MadExcept 默认错误。

      【讨论】:

        【解决方案6】:

        任何未在特定级别明确或一般处理的异常都将在调用堆栈中向上传播。 Delphi RTL(运行时库)将生成一组不同的异常类——(数学错误、访问错误、类特定错误等)。您可以选择在不同的 try except 块中专门或一般地处理它们。

        您实际上不需要声明任何新的异常类,除非您需要传播带有异常的特定功能上下文。

        正如之前的评论者所写,您还可以添加所有异常处理程序(如 MadExcept 或 EurekaLog)的母亲来捕获未捕获的内容。

        编辑:这是针对未处理异常的全面保险

        try
          ThisFunctionMayFail;
        except
          // but it sure won't crash the application
          on e:exception
          do begin
            // something sensible to handle the error 
            // or perhaps log and/or display the the generic e.description message
          end
        end;
        

        【讨论】:

          【解决方案7】:

          【讨论】:

          • 我们已经在使用 madExcept。但我正在寻找一种在设计时找到未捕获异常的方法。我一直在寻找某种可以涵盖此问题的代码分析工具,但没有找到。
          【解决方案8】:

          对于运行时尝试Eurekalog。我不知道设计时是否存在工具。即使您有没有源代码的第三方代码,您也会遇到更多困难。 Delphi 不需要捕获异常,因此您不必像在 Java 中那样声明它们。

          我想说的是,Delphi 不需要处理异常。它只会终止程序。 EurekaLog 提供了记录已处理和未处理异常的方法,并提供了有关异常发生时程序状态的大量信息,包括异常发生的代码行和当时的调用堆栈。

          【讨论】:

          • 如果某事引发异常,我会说需要捕获它,否则它将在运行时作为未处理的异常出现。问题是如何确保真正处理所有引发的异常。
          • madExcept 是更好的选择。 jedi jclDebug 是另一种选择(免费)。
          【解决方案9】:

          正如 Jim McKeeth 指出的那样,您无法得到明确的答案,但在我看来,可以通过一些静态分析部分回答这个问题:给定一个特定的函数/过程,构造调用图。检查该调用图中的每个函数以获取 raise 语句。例如,这会告诉您 TIdTcpClient.ReadString 可以引发 EIdNotConnected(等等)。

          聪明的分析员可能还会注意到某些代码使用 / 运算符并可能包含 EDivByZero,或者某些过程访问数组并包含 ERangeError。

          这个答案比简单地寻找“加注”要严格一些。

          【讨论】:

            【解决方案10】:

            单元的终结部分也可能引发异常。我认为这些会溜走……而且也有些问题。

            我认为 Delphi IDE 有一个内置的“堆栈跟踪”或“堆栈树”之类的东西。

            这个问题让我想起了 Skybuck 的 TRussianRoulette 游戏……谷歌一下,它的代码和答案可能会有所帮助。

            【讨论】:

              猜你喜欢
              • 2011-05-30
              • 2010-09-20
              • 2012-12-02
              • 2020-04-06
              • 1970-01-01
              • 1970-01-01
              • 2022-07-27
              • 2017-08-13
              • 1970-01-01
              相关资源
              最近更新 更多