Delphi异常处理,使用E:Exception或ExceptObject
Delphi exception handling, use E: Exception or ExceptObject
我们有 2 个应用程序,第一个是 VCL 项目,另一个是 windows 服务。
在我们做的VCL项目中:
try
except
on E: Exception do
// do something with E.Message
end
但在 windows 服务(使用多个线程)中我们使用:
try
except
// do something with Exception(ExceptObject).Message
end
我从同事那里得到的信息是"We must use ExceptObject in threads and E: Exception in applications that use GUI"。但是我找不到任何关于这个的东西。
我在这里找到了一个示例 http://edn.embarcadero.com/article/10452,它使用实例变量存储异常并使用 ExceptObject,但没有给出原因的解释。
这个 ExceptObject 是否是线程安全的(因为它来自单元 'System')?
那么在 Delphi 中处理异常的正确方法是什么?为什么有不止一种方法?
异常处理没有正确的方法。只有一种方法。可能会让您感到困惑的是处理创建的异常对象,它 导致 引发异常,但其生命周期在这里对您来说最重要。
一般来说,只有两种方法可以处理那些异常对象。要么让它们在异常块范围之外存活并自行释放它们,要么在异常块结束时让它们通过 RTL 释放。
但是要回答我猜你问的问题。 Exception class 不是线程安全的。而且,您的同事错了,因为没有人被迫在线程中使用特定的异常处理。无论如何,这些规则对于进程创建的所有线程都是相同的。只是,那些异常对象在异常块中可以不稳定:
1。从 ExceptObject
获取当前异常对象
ExceptObjectreturns当前异常对象。实际上,它可能会导致这种情况;如果您将此类对象引用存储到异常处理程序块内的变量中,并且将在该块内引发另一个异常,则该存储的实例可能会变得无效。这很不安全。
但这并不意味着您不能引用此类对象并使用某些同步机制将其传递给另一个线程(因为它不是线程安全的 class)并在那里使用它。您只需要注意不会引发其他异常,因为这会使先前存储的对象无效,因此您必须从调用者的角度处理异常处理程序中的 staying 和你必须使用一种线程同步机制。
因此,实际上使用从 on 表达式获取的异常对象比使用 ExceptObject 更稳定。但同样的规则也适用于此;您需要将来自 on 表达式的对象实例与另一个线程同步(因为它不是线程安全的 class),但在这种情况下,从 on 表达式不会像 ExceptObject 可以在特定异常块中更改。
2。使用 AcquireExceptionObject
保留异常对象
AcquireExceptionObject 函数允许您保持异常对象 活动 甚至在异常块之外。
对于线程同步时的异常处理,我建议您使用 AcquireExceptionObject 函数,它使异常对象 免费 可以使用,即使在异常块结束。对于带来唯一责任的您,通过调用 ReleaseExceptionObject 过程或再次引发此对象的异常来释放此类获取的对象。
维多利亚完全正确。
个人比较喜欢这个成语:
try
...
except
// IO error
On E : EInOutError do
ShowMessage('IO error : '+E.Message);
// Division by zero
On E : EDivByZero do
ShowMessage('Div by zero error : '+E.Message);
// Catch other errors
else
ShowMessage('Unknown error');
end;
详细说明:
维多利亚说"There is no right way for exception handling. There is just one way."完全正确。
你得到的关于 "use one syntax for threads, and the other for GUIs" 的建议完全是错误的。 "threads" 与 "GUI" 没有 "different syntax"。那是胡说八道:(
我更喜欢在 exception
块中使用 on : MyExceptionType
。
我也比较喜欢区分不同的异常类型,whenever/wherever可能。
您引用的示例 http://edn.embarcadero.com/article/10452 涉及如何在您不处理特定线程中的异常时避免可能的访问冲突。将异常实例保存在成员变量中有助于缓解此问题。
以下 link 可能有助于澄清:
我们有 2 个应用程序,第一个是 VCL 项目,另一个是 windows 服务。
在我们做的VCL项目中:
try
except
on E: Exception do
// do something with E.Message
end
但在 windows 服务(使用多个线程)中我们使用:
try
except
// do something with Exception(ExceptObject).Message
end
我从同事那里得到的信息是"We must use ExceptObject in threads and E: Exception in applications that use GUI"。但是我找不到任何关于这个的东西。
我在这里找到了一个示例 http://edn.embarcadero.com/article/10452,它使用实例变量存储异常并使用 ExceptObject,但没有给出原因的解释。
这个 ExceptObject 是否是线程安全的(因为它来自单元 'System')?
那么在 Delphi 中处理异常的正确方法是什么?为什么有不止一种方法?
异常处理没有正确的方法。只有一种方法。可能会让您感到困惑的是处理创建的异常对象,它 导致 引发异常,但其生命周期在这里对您来说最重要。
一般来说,只有两种方法可以处理那些异常对象。要么让它们在异常块范围之外存活并自行释放它们,要么在异常块结束时让它们通过 RTL 释放。
但是要回答我猜你问的问题。 Exception class 不是线程安全的。而且,您的同事错了,因为没有人被迫在线程中使用特定的异常处理。无论如何,这些规则对于进程创建的所有线程都是相同的。只是,那些异常对象在异常块中可以不稳定:
1。从 ExceptObject
获取当前异常对象ExceptObjectreturns当前异常对象。实际上,它可能会导致这种情况;如果您将此类对象引用存储到异常处理程序块内的变量中,并且将在该块内引发另一个异常,则该存储的实例可能会变得无效。这很不安全。
但这并不意味着您不能引用此类对象并使用某些同步机制将其传递给另一个线程(因为它不是线程安全的 class)并在那里使用它。您只需要注意不会引发其他异常,因为这会使先前存储的对象无效,因此您必须从调用者的角度处理异常处理程序中的 staying 和你必须使用一种线程同步机制。
因此,实际上使用从 on 表达式获取的异常对象比使用 ExceptObject 更稳定。但同样的规则也适用于此;您需要将来自 on 表达式的对象实例与另一个线程同步(因为它不是线程安全的 class),但在这种情况下,从 on 表达式不会像 ExceptObject 可以在特定异常块中更改。
2。使用 AcquireExceptionObject
保留异常对象AcquireExceptionObject 函数允许您保持异常对象 活动 甚至在异常块之外。
对于线程同步时的异常处理,我建议您使用 AcquireExceptionObject 函数,它使异常对象 免费 可以使用,即使在异常块结束。对于带来唯一责任的您,通过调用 ReleaseExceptionObject 过程或再次引发此对象的异常来释放此类获取的对象。
维多利亚完全正确。
个人比较喜欢这个成语:
try
...
except
// IO error
On E : EInOutError do
ShowMessage('IO error : '+E.Message);
// Division by zero
On E : EDivByZero do
ShowMessage('Div by zero error : '+E.Message);
// Catch other errors
else
ShowMessage('Unknown error');
end;
详细说明:
维多利亚说"There is no right way for exception handling. There is just one way."完全正确。
你得到的关于 "use one syntax for threads, and the other for GUIs" 的建议完全是错误的。 "threads" 与 "GUI" 没有 "different syntax"。那是胡说八道:(
我更喜欢在
exception
块中使用on : MyExceptionType
。我也比较喜欢区分不同的异常类型,whenever/wherever可能。
您引用的示例 http://edn.embarcadero.com/article/10452 涉及如何在您不处理特定线程中的异常时避免可能的访问冲突。将异常实例保存在成员变量中有助于缓解此问题。
以下 link 可能有助于澄清: