如何找出Delphi函数可能抛出的异常?

时间:2008-09-16 14:00:11

标签: delphi exception-handling

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

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

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

10 个答案:

答案 0 :(得分:12)

(编辑:现在很明显,这个问题仅仅 来进行设计时检查。)

新答案:

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

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

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

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

(先前的回答: 可以指定Application.OnException事件处理程序来捕获未由其他异常处理程序处理的所有异常。虽然这是运行时,因此可能并不完全是你所追求的(听起来你想在设计时识别它们),它确实允许你捕获任何其他地方未处理的异常。与Jedi Code Library中的JCLDebug之类的工具结合使用,您可以记录堆栈跟踪以找出&为什么会发生异常,这将允许进一​​步调查并在有罪代码周围添加特定的异常处理或预防......

答案 1 :(得分:11)

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

编写良好的代码将记录可以引发的不同异常,以便您可以以有意义的方式处理它们。不推荐使用Catch-all处理程序,因为如果您不知道引发异常的原因,实际上无法知道该怎么做。我也强烈推荐madExcept。

答案 2 :(得分:5)

除了对“raise”关键字进行扫描之外,Delphi中没有语言构造告诉随意的读者可以从方法中预期哪些例外。

在运行时,可以在每个方法中添加一个catch-all异常处理程序,但这是不可取的,因为它会降低执行速度。 (这也很麻烦。)

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

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

答案 3 :(得分:5)

简短的回答是,没有任何工具能够满足您的要求,即使扫描提升关键字也无法实现这一目标。 EAccessViolation EOutOfMemory 只是可以在任何地方引发的众多异常中的两个。

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

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

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

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

答案 4 :(得分:4)

任何未明确或通常在特定级别处理的异常都会在调用堆栈中向上涓流。 Delphi RTL(运行时库)将生成一组不同的异常类 - (数学错误,访问错误,类特定错误等)。您可以选择专门处理它们,或者通常在不同的块中处理它们。

除非需要传播具有异常的特定功能上下文,否则不需要声明任何新的异常类。

正如之前的评论者所写,你也可以添加像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;

答案 5 :(得分:4)

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

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

答案 6 :(得分:3)

答案 7 :(得分:1)

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

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

答案 8 :(得分:1)

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

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

这个答案比仅仅为了“加注”更加紧凑。

答案 9 :(得分:0)

单位的终结部分也可以引发异常。我觉得这些会滑落......而且也有些问题。

我认为Delphi IDE有一个内置的堆栈跟踪&#34;或者&#34;堆栈树&#34;类似的东西。

这个问题让我想起了Skybuck的TRussianRoulette游戏... google it,它的代码和答案可能有所帮助。