我们有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
我从同事那里获得的信息是"我们必须在线程中使用ExceptObject,在使用GUI"的应用程序中使用E:Exception。但我无法找到任何与此相关的信息。
我在这里找到了一个例子http://edn.embarcadero.com/article/10452,它使用一个实例变量来存储异常并使用ExceptObject,但没有解释原因。
这个ExceptObject是否是线程安全的(因为它来自单位' System')?
那么在Delphi中处理异常的正确方法是什么?为什么有多种方法可以实现呢?
答案 0 :(得分:8)
没有正确方法进行异常处理。只有一种方法。可能会让您感到困惑的是处理创建的异常对象,以及哪些导致引发异常,但其生命周期对您来说是最重要的。
一般来说,只有两种处理这些异常对象的方法。要么让它们超出异常块范围,要么自己释放它们,要么在异常块结束时让它们由RTL释放。
但要回答我猜你的问题。 Exception类不是线程安全的。而且,你的同事错了,因为没有人被迫在线程中使用特定的异常处理。无论如何,这些规则对于流程创建的所有线程都是相同的。只是,这些异常对象可以在异常块中不稳定:
ExceptObject返回当前的异常对象。在实践中,它可能会导致这种情况;如果将此类对象引用存储到异常处理程序块内的变量中,并且此类块中将引发另一个异常,则该存储的实例可能变为无效。这是非常不安全的。
但它并不意味着你不能引用这样的对象并通过使用一些同步机制将它传递给另一个线程(因为它不是线程安全类)并在那里使用它。您只需要注意不会引发其他异常,因为这会使先前存储的对象无效,因此您必须从调用者的角度处理保留在异常处理程序中你必须使用一种线程同步机制。
因此,实际使用从 on 表达式获取的异常对象可以比使用ExceptObject更稳定。但同样的规则也适用于此;您需要将 on 表达式中的对象实例与另一个线程同步(因为它不是线程安全类),但在这种情况下,从 on 表达式不会被改变,不像ExceptObject表达式可以在某个异常块中。
AcquireExceptionObject函数允许您将异常对象保持活动甚至超出异常块。
对于谈论线程同步时的异常处理,我建议你使用AcquireExceptionObject函数使异常对象 free 消耗,即使异常块结束。对于带来唯一责任的人,通过调用ReleaseExceptionObject过程或再次通过此对象引发异常来释放此类获取的对象。
答案 1 :(得分:6)
维多利亚是绝对正确的。
就个人而言,我非常喜欢这个成语:
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;
详细说明:
Victoria说"没有正确的方法进行异常处理。只有一种方式。"这绝对是正确的。
你得到的建议"为线程使用一种语法,另一种用于GUI"是完全错的。没有"不同的语法"对于"线程"与#34; GUI"。那是胡说八道:(
我更喜欢在on : MyExceptionType
区块中使用exception
。
我也希望随时/尽可能区分不同的异常类型。
您引用的示例http://edn.embarcadero.com/article/10452介绍了如果您不在该特定线程中处理异常,如何避免可能的访问冲突。将异常实例保存在成员变量中有助于缓解此问题。
以下链接可能有助于澄清: