Manchmal möchte man etwas trotz Fehler/Exceptions fertig durcharbeiten lassen...
Nun gibt es da mehere Wege:
[*] der böse Weg = einfach den/die Fehler ignorieren
ich glaub hier sind wir und einige, daß man sowas nicht macht.
Delphi-Quellcode:
var
i: Integer;
begin
for i := 1 to 5 do
try
// ...
except
end;
Stand selber grad vor diesem Problem, denn in einer Schleife müssen unbedingt alle Werte abgearbeitet werden,
aber dennoch sollte die
Exception nicht verschwinden.
Da es sich hier nur um ein Zusatzmodul (himXML
) handelt
und im aufrufenden Code eine etwaige
Exception dennoch ankommen soll/muß,
ist schonmal klar, daß der "böse Weg" absolut nicht in Frage kommt.
Ich war schon kurz davor hier zu fragen, was andere da machen würden,
aber wärend ich den Beitrag schrieb, da fiehl mir grade noch so ein Tipp ein, welchen mir her jemand vor 'ner Weile mal gegeben hatte ... AcquireExceptionObject.
[*] also würde man es sich merken, ob eine
Exception auftrat und diese später behandeln
nur blöde, daß hier keine mehr weiß, was mal war
Delphi-Quellcode:
var
i: Integer;
Fehler: Boolean;
begin
Fehler := False;
for i := 1
to 5
do
try
// ...
except
Fehler := True;
end;
if Fehler
Then
Raise Exception.Create('
Irgendein Fehler ist aufgetreten, '
+ '
aber ich weiß nicht mehr welcher ._.');
[*] also noch mehr merken
hier hätten wir zwar den Text, aber für eine weitere Fehlerbehandlung ist nun die ursprüngliche
Exception selber futsch
Delphi-Quellcode:
var
i: Integer;
Fehler:
String;
begin
Fehler := '
';
for i := 1
to 5
do
try
// ...
except
on e:
Exception do
Fehler := e.
Message;
end;
if Fehler <> '
'
Then
Raise Exception.Create(Fehler);
[*] warum dann nicht gleich alles merken?
Delphi-Quellcode:
var
SavedExcept:
Exception;
i: Integer;
begin
SavedExcept :=
nil;
try
for i := 1
to 5
do
try
// ...
except
if not Assigned(SavedExcept)
then
SavedExcept := AcquireExceptionObject;
end;
finally
if Assigned(SavedExcept)
then
raise SavedExcept;
end;
end;
Hier wäre es dann so, wie gewollt.
Die komplette
Exception bleibt erhalten, also samt Message und
Exception-Klasse.
hier nochmal ein Beispiel
Delphi-Quellcode:
procedure Test;
var
SavedExcept:
Exception;
i: Integer;
begin
SavedExcept :=
nil;
try
for i := 1
to 5
do
try
// ...
if i
in [2..4]
then
raise Exception.CreateFmt('
Durchlauf %d', [i]);
// ...
except
if not Assigned(SavedExcept)
then
SavedExcept := AcquireExceptionObject;
end;
finally
if Assigned(SavedExcept)
then
raise SavedExcept;
end;
end;
Nach außen hin wäre es so, als wenn die Prozedur im 2. Durchgang abgebrochen wäre
und man erhält auch die (erste)
Exception davon.
Dennoch wurde aber die Schleife noch komplett abgearbeitet.
[*] und, entsprechend eines Vorschlages,
noch die "Extremvariante"
hier wird eine Liste aller Exceptions gespeichert
und nicht nur die Erste, so wie in den vorhergehenden Beispielen.
Delphi-Quellcode:
type
EMultiException =
class(
Exception)
protected
FList:
Array of Exception;
function GetCount: Integer;
function GetExcept(i: Integer):
Exception;
public
constructor Create(E:
Exception);
destructor Destroy;
override;
class procedure AddLastException(
var SavedExcept:
Exception);
class procedure Reraise(SavedExcept:
Exception);
property SubExceptCount: Integer
read GetCount;
property SubException[i: Integer]:
Exception read GetExcept;
end;
function EMultiException.GetCount: Integer;
begin
Result := Length(FList);
end;
function EMultiException.GetExcept(i: Integer):
Exception;
begin
if (i >= 0)
and (i < Length(FList))
then
Result := FList[i]
else Result :=
nil;
end;
constructor EMultiException.Create(E:
Exception);
begin
SetLength(FList, 1);
FList[0] := E;
Message := FList[0].
Message;
HelpContext := FList[0].HelpContext;
end;
destructor EMultiException.Destroy;
var
i: Integer;
begin
for i := 0
to High(FList)
do FList[i].Free;
inherited;
end;
class procedure EMultiException.AddLastException(
var SavedExcept:
Exception);
begin
if not Assigned(SavedExcept)
Then
SavedExcept := AcquireExceptionObject
else if not (SavedExcept
is EMultiException)
then begin
SavedExcept := EMultiException.Create(SavedExcept);
EMultiException.AddLastException(SavedExcept);
end else
with EMultiException(SavedExcept)
do begin
SetLength(FList, Length(FList) + 1);
FList[High(FList)] := AcquireExceptionObject;
end;
end;
class procedure EMultiException.Reraise(SavedExcept:
Exception);
begin
if Assigned(SavedExcept)
then
raise SavedExcept;
end;
verwendet wird es z.B. so
Delphi-Quellcode:
var
SavedExcept:
Exception;
i2: Integer;
begin
SavedExcept :=
nil;
try
for i2 := 1
to i
do
try
// ...
except
EMultiException.AddLastException(SavedExcept);
end;
finally
EMultiException.Reraise(SavedExcept);
end;
end;
und noch ein kleines Beispiel:
Delphi-Quellcode:
procedure Test(i: Integer);
var
SavedExcept:
Exception;
i2: Integer;
begin
SavedExcept :=
nil;
try
for i2 := 1
to i
do
try
// ...
raise EExternalException.CreateFmt('
Test %d', [i2]);
// ...
except
EMultiException.AddLastException(SavedExcept);
end;
finally
EMultiException.Reraise(SavedExcept);
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
i: Integer;
S:
String;
begin
try
Test(1);
except
on E:
Exception do
ShowMessage(Format('
%s: "%s"', [E.ClassName, E.
Message]));
end;
try
Test(3);
except
on E: EMultiException
do
begin
S := Format('
%s: "%s"'#13#10'
*********************', [E.ClassName, E.
Message]);
for i := 0
to E.SubExceptCount - 1
do
S := Format('
%s'#13#10'
%s: "%s"',
[S, E.SubException[i].ClassName, E.SubException[i].
Message]);
ShowMessage(S);
end;
on E:
Exception do
ShowMessage(Format('
%s: "%s"', [E.ClassName, E.
Message]));
end;
end;
Zitat:
---------------------------
Project1
---------------------------
EExternalException: "Test 1"
---------------------------
OK
---------------------------
---------------------------
Project1
---------------------------
EMultiException: "Test 1"
*********************
EExternalException: "Test 1"
EExternalException: "Test 2"
EExternalException: "Test 3"
---------------------------
OK
---------------------------