Da wird man wohl diese Sprachunschönheit akzeptieren müssen und doppelt aufbauen
Das ist Geschmackssache. In C# gehts auch nicht und das ist auch OK so (
imho). Die Abstraktionsniveaus passen bei 'try-finally' und 'try..except' sowieso nicht, ergo ist es eh ein Designflaw, das in eine Methode zu packen, aber das mal nur nebenbei.
Ist ein except nicht irgendwie ein finally.
Wenn Du es 'falsch' angehst: Ja.
Das 'Try-Except' benötigst Du, um etwaige Ausnahmen/Fehler zu kapseln und das Abstraktionsniveau anzuheben. Allgemein sieht das so aus:
Delphi-Quellcode:
procedure TMyClass.Action();
begin
try
DoSomething();
except
on e:ESomethingException
do
raise new EActionException.Create (TranslateExpectedException(e));
on e:
Exception do
raise new EActionException.Create (TranslateUnexpectedExpectedException(e));
end
end;
D.h. Du fängst die Exceptions ab und übersetzt sie so, das der Aufrufer der Methode 'Action' etwas damit anfangen kann. Z.B. kapselst Du Fehlermeldungen beim Verbindungsaufbau der
DB (
TCP-, Named-Pipe-, Server-, Hardware-, Login- Fehler in eine abstraktere 'EActionFailed'-
Exception. Denn den Aufrufer interessiert es nicht, was da hinter der Fassade vor sich geht und ob es eine EADOException, EOracleException, ETCPException, EIdException etc. ist.
Allgemein gesehen transformierst Du die
Exception und reichst sie durch. In Sonderfällen, wenn z.B. die
Exception einfach eine Ausnahme von der Regel ist, oder wenn die
Exception 'repariert' werden kann, würdest Du die
Exception nicht weiterreichen bzw. transformieren.
Damit ist klar, das dein Gleichsetzen nur in Ausnahmefällen zutreffen würde. Aus Gründen der Übersichtlichkeit würde ich jedoch *immer* ein explizites 'try-finally' umsetzen. Dann ist einfach sonnenklar, das es sich um einen resourcenschutzblock handelt.
Delphi-Quellcode:
Procedure TMyClass.Action();
// Public !
Begin
Try
InnerAction();
Except
on e:ESomethingException
do
raise new EActionException.Create (TranslateExpectedException(e));
on e:
Exception do
raise new EActionException.Create (TranslateUnexpectedExpectedException(e));
end
end;
Procedure TMyClass.InnerAction();
// private oder protected !!
begin
Stuff.Acquire();
try
DoSomething(Stuff);
Finally
Stuff.Release();
End
End;
Nun kann man in 'Action' entscheiden, ob man reparieren kann, oder nicht.
Es geht natürlich auch umgekehrt:
Delphi-Quellcode:
Procedure TMyClass.Action();
// Public !
Begin
Stuff.Acquire();
Try
InnerAction(Stuff);
Finally
Stuff.Release();
End
end;
Procedure TMyClass.InnerAction(Stuff : TStuff);
// private oder protected !!
begin
try
DoSomething(Stuff);
Except
on e:ESomethingException
do
raise new EActionException.Create (TranslateExpectedException(e));
on e:
Exception do
raise new EActionException.Create (TranslateUnexpectedExpectedException(e));
end
End;
Meist wird man die erste Variante ('
Unit of Work') verwenden. Bei der zweiten Variante ist ja nicht sichergestellt, das 'Stuff' korrekt initialisiert ist (das müsste ggf. sichergestellt werden). Allerdings könnte die 2. Variante bei Reparaturversuchen sinnvoll sein. Kommt immer auf den Fall an.