【发布时间】:2025-11-28 09:20:03
【问题描述】:
我已将 Application.OnException 设置为自定义异常处理程序,以便我可以记录崩溃并提供退出选项。但是,我现在发现它甚至可以在我已经处理过的异常上运行,例如,在验证数字输入时出现的异常。有没有办法让自定义异常处理程序只在未处理的异常上运行?
编辑:事实证明,当我在调试器之外运行时,我得到了预期的行为。也许这只是一个调试器的事情。至少可以说,我认为 Delphi 调试器与异常的交互并不直观。
【问题讨论】:
我已将 Application.OnException 设置为自定义异常处理程序,以便我可以记录崩溃并提供退出选项。但是,我现在发现它甚至可以在我已经处理过的异常上运行,例如,在验证数字输入时出现的异常。有没有办法让自定义异常处理程序只在未处理的异常上运行?
编辑:事实证明,当我在调试器之外运行时,我得到了预期的行为。也许这只是一个调试器的事情。至少可以说,我认为 Delphi 调试器与异常的交互并不直观。
【问题讨论】:
如果调试器内部和外部的行为发生变化,那么告诉您异常的并不是真正的您的程序。我在我的网站上写过这个现象:
Why do I continue getting error messages even after I have written an exception handler?
摘录:
在默认设置下,Delphi IDE 会在您的程序中发生异常时通知您...。重要的是要意识到此时,您的程序的异常处理代码还没有运行。都是德尔福本身;它作为调试器的特殊地位允许它在您的程序中获得任何异常的第一通知,甚至在您的程序知道它之前。
在您关闭 Delphi 的消息框后,执行将暂停在您的源代码中 Delphi 可以找到代表异常源的最佳行。按“运行”按钮让您的程序恢复。控制将传递到下一个 finally 或 except 堵塞。在恢复程序之前,您可以使用各种可用的调试工具。您可以检查范围内任何变量的值,甚至可以修改它们的值。
那么,你如何通知 Delphi 你已经处理了一个异常?你没有——因为你的程序还没有处理它。为什么调试器不能检测您的程序是否正在处理异常?因为为了做到这一点,它需要进一步执行你的程序。检测缺少异常处理程序就像解决停机问题。确定是否要处理异常的唯一方法是让程序运行,然后查看异常是否得到处理。但是到那时,进行任何调试都为时已晚,因此调试器别无选择,只能在第一次检测到异常时暂停您的程序,然后让您从那里弄清楚该怎么做。
我的文章继续描述了一些可以避免让调试器捕获某些异常的方法,总结如下:
我的文章中没有包含其他选项:
您说您正在验证数字输入。这对我来说听起来就像你正在做一些事情,比如调用StrToInt,然后在输入不是有效整数时捕获EConvertError 异常。这是一种验证输入的昂贵方式。取而代之的是,使用TryStrToInt,它将告诉您转换是否成功,或者使用StrToIntDef,它将默默地返回一个默认值而不是引发异常。另一个选项是普通的Val,它尝试转换字符串,如果失败,它会告诉您字符串中的哪个位置导致失败。如果您想使用尽可能多的字符进行转换,然后在下一个非数字字符处继续解析,Val 特别有用。
【讨论】:
引用关于 TApplication.OnException 的文档 (Delphi 7)
"Use OnException to change the default behavior that occurs when an exception is not
handled by application code."
所以:OnException 事件处理程序中只有 未处理的异常 可用。您遇到的可能是 Delphi IDE 打破了异常。这是(至少在 Delphi 7 中)可配置的。
在 Delphi 7 中,您可以通过单击“工具”->“调试器选项”菜单对其进行配置。然后选择“Language Exceptions”并取消勾选“Stop on Delphi exceptions”复选框。但是在其他 delphi 版本中可能会有所不同。
【讨论】:
另一种方法可能是不使用 Application.OnException。但是要简单地捕获“主”函数中的所有异常。这样你就可以捕获之前没有缓存的所有异常,记录异常,然后崩溃。
【讨论】:
Application.OnException 应该只针对未处理的异常触发。在 try-except 块中重新引发异常将导致异常由 Application.OnException 处理。对于引发异常的输入验证,您可以向用户显示一条消息,然后仅当您希望将其记录到错误日志中时才重新引发异常。
【讨论】: