3 回答
Why don't to use this:
try
...
except
on EAssertionFailed do raise;
on E: .... do ... ; // your exception
on E: .... do ... ; // your exception
on E: .... do ... ; // your exception
on E: Exception do ... ; // all other exceptions
end;
If any of the handlers in the exception block matches the exception, control passes to the first such handler. An exception handler 'matches' an exception just in case the type in the handler is the class of the exception or an ancestor of that class.
Or you can remove on EAssertionFailed do raise;
and on E: Exception do ... ;
from the exception block and then exception handler will be searched in the next-most-recently entered try...except statement that has not yet exited.
I'm offering my own answer here to see what the community thinks.
The point wasn't a misunderstanding of how exception handling works in Delphi. I've summarised the particular problem in my update to the question.
My solution is going to be to convert the many different exception types the library can raise into a single type that I can handle explicitly. I'll put a blanket exception handler around the one problem call to the library. This handler will raise a new exception of a known type, to be caught explicitly higher up at the appropriate time.
(And no, the exceptions raised by the library call do not have any common base type other than Exception itself, so I really do have to catch all exceptions if I want to recover from a failure in the library call.)
Crucially, I believe that although I cannot hope to enumerate all the exceptions that this library call could raise, I can be sure that it won't put the application into an unstable state when it raises an exception.
Update
In the end I was able to use something like this:
on e:Exception do
begin
if (e.ClassType = Exception) or (e is EConvertError) or
(e is EVariantError) then
begin
ShowMessage('The application settings could not be loaded.');
end
else
begin
// An exception we didn't anticipate. Assume it is fatal.
raise;
end;
end;
A lot of the recoverable exceptions raised by the library are of type Exception
, but note that only Exception
and the specified descendants are handled. The others are raised indirectly by the runtime library. There might turn out to be other exceptions that should be handled too, but this seems like a good start. It's better to have the application bail out when it needn't have done so than to continue running and corrupt the user's data.