|
| |
Exceptions - Part 1
Author: A. M. Elarigh
|
Exceptions
are not errors
Exceptions
are not errors (i.e. EAbort example is not an error), but a mechanism provided by Delphi to help you raise,
detect and response to errors in
an elegant and standard way.
The exceptions mechanism is used when some unexpected exceptional situation
is encountered (an error or other event) that forces the normal execution of
your code to be interrupted. Exceptions, if used properly, can help you
recover from serious errors or at least end your application with a
friendly message to the user, rather than a default one.
As the Delphi help documentation says:
"Exceptions are exceptional conditions that
require special handling".
Exceptions are classes
Exceptions are represented by classes, and every
exception class is a subclass of an ultimate root class named
"Exception" or one of its descendants.
The
Exception class is defined in
the SysUtils unit:
type
Exception = class(TObject)
private
FMessage: string;
FHelpContext: Integer;
public
constructor Create(const Msg:
string);
constructor CreateFmt(const Msg:
string; const Args:
array of const);
...
end;
type
EExternal = class(Exception)
....
end;
EIntError =
class(EExternal);
EDivByZero = class(EIntError);
ERangeError = class(EIntError);
EIntOverflow = class(EIntError);
EMathError =
class(EExternal);
EInvalidOp = class(EMathError);
EZeroDivide = class(EMathError);
EOverflow = class(EMathError);
EUnderflow = class(EMathError);
EConvertError =
class(Exception);
EExternal
is a subclass of the root class
Exception and
EIntError
is a subclass of
EExternal. EDivByZero
(for integer), ERangeError
and
EIntOverflow
are all subclasses of
EIntError. EZeroDivide
(for floating-point) is a subclass of
EMathError which in turn is a
subclass ofEExternal.
The
SysUtils automatically converts most of the runtime errors into exceptions.
The Message
property is to report information about the exception
when it is created (raised) to the caller code.
Inheritance and Exception
Using the flexible
power of class inheritance,
exception classes can be
grouped
into subhierarchies
to intreduce a related types of exceptions (see the
declarions above), and
you can also expand the
existing exceptions by
defining your own to
represent more specific
exceptions,
for example:
type
EMyConvertError = class(EConvertError);
EPasswordInvalid = class(Exception);
|
Raising
exceptions
( the raise
statement)
The exception system allows
us to force an
exception
to occur
(for example, to indicate an
error condition), anywhere in our code .This is simply
done by invoking an
explicit raise
statement which
raises an exception of a
specific type:
raise ESomeException.Create('Be
warned .... ');
As you can see, we write
the reserved word raise, then follow
it by an instance of
an any exception object that was
declared somewhere.
To make your life easier and help you get better
understanding of the concepts, recall the definition of StrToInt()
function in the SysUtils.
procedure ConvertErrorFmt(ResString: PResStringRec; const Args: array of
const);
begin
raise EConvertError.CreateResFmt(ResString,
Args);
end;
function StrToInt ( const S: string ): Integer;
var
E: Integer;
begin
Val(S, Result, E);
if E <> 0 then ConvertErrorFmt(@SInvalidInteger, [S]);
end;This function tries to convert a string
representaion of an integer to
an equivelant number and if the
string does not represent a valid number, the function
simply raises an EConvertError exception.
So, the steps needed to raise an exception are as simple
as:
- Declaring a new exception class
or choose a predefined one.
- Write a raise
statement
as above.
|
|
Handling the exception (try..except
construct)
Example
var
I: Integer;
begin
I := StrToInt('123');
I :=
StrToInt('12c'); // an error ..execution stops here
I :=
StrToInt('456'); // this will not execute
ShowMessage(IntToStr(I));
end;
Here, we intentionally raise the
subexception
EConvertError.
Without writing a handler, a default message,
" '12c' is not a valid integer
value' ".
To respond to the exception and
correct the situation, you must enclose your code in a "try..except"
construct,
between the keywords try and except
(the detection block).
The exception handler
(response block) should immediately follow the
except keyword, For eexample:
var
I: Integer;
begin
try
I :=
StrToInt('123');
I :=
StrToInt('12c'); // an error ..execution stops here
I :=
StrToInt('456'); // this will not execute
ShowMessage(IntToStr(I));
except
ON E: Exception do
ShowMessage('E.Message'+ E.Message+' : '+ ' Please try
again');
end;
end;
|
|
|
|
The syntax of a try...except statement is
try
statements
//
detection block
except
exceptionBlock
end;
The exception block
can be just a sequence of
statements without any exception handlers,
then these statements
will be executed and the
exception is concidered to
handled whatever the type of exception is.
The special case when there is no statement
at all, that is, except
is immediately followed by an end,
then this too is considered handled
In both cases, the type of the
exception
is not known.
The
exception Block can be a
sequence of on statements,
optionally followed by an else
on
identifier: exceptiontype
do statement
identifier {optional}: is
a normal pascal identifier
and is ,
exception type:
is a type used to represent exceptions,
statement: is any
statement.
for example:
try
...
except
on
EZeroDivide do HandleZeroDivide;
on
EOverflow do HandleOverflow;
on
EMathError do HandleMathError;
end;
|
|
to be continued ... |
|
Links to exception handler articles
|
|