Da die Funktion zwei Aufgaben erfüllt (sende Nachrichten und räume auf), teilen wir sie. Da ein Goto zu 99.9% der Fälle eine Aufgabe beendet, fällt das Goto nun automatisch weg. Das ist kein Trick, sondern sowieso Pflicht, um das SRP (Single Responsibility Princip) auf funktionaler Ebene einzuhalten.
Delphi-Quellcode:
procedure TryHardToSendMessages (aParentHandle : THandle);
var
i: Integer;
begin
for i := 0 to 9 do begin
if Abort then begin
SendMessage(ParentHandle, CM_ABORT, 0 , 0);
exit;
end;
SendMessage(ParentHandle, CM_STATUS, Integer(PChar('Durchlauf:')), i);
Sleep(500);
end;
SendMessage(ParentHandle, CM_FINISHED, 0, 0);
End;
function DemoThread(p: Pointer): Integer;
begin
Try
TryHardToSendMessages (PThreadParams(p)^.ParentHandle);
Finally
Dispose(p);
End;
Result := 0;
end;
Hmm. Das mit der Schleife und dem Abort-Flag geht ja nun mal gar nicht (Abort ist ein reserviertes Schlüsselwort):
Außerdem und überhaupt ist nicht so richtig klar, wie die Nachrichten verwendet werden sollen. Mal sehen:
Wir senden 10x eine Nachricht 'CM_STATUS'. Nach jeder Nachricht warten wir 500ms.
Wenn alle 10 Nachrichten verschickt haben, senden wir ein 'CM_FINISHED'.
Wurden wir ausnahmsweise (<-Zaunpfahl) unterbrochen, senden wir ein CM_ABORT.
Delphi-Quellcode:
Procedure TryHardToSendMessages (aParentHandle : THandle);
var
i: Integer;
begin
Try
for i := 0 to 9 do
if ExternalAbort then
abort
else begin
SendMessage(ParentHandle, CM_STATUS, Integer(PChar('Durchlauf:')), i);
Sleep(500);
end
SendMessage(ParentHandle, CM_FINISHED, 0, 0);
Except
// TODO: Vollständige Exceptionbehandlung
SendMessage(ParentHandle, CM_ABORT, 0 , 0);
end;
end;
Hier eine Alternative ohne Exceptions, sondern mit einer Funktion, die den Erfolg als Rückgabewert liefert.
Delphi-Quellcode:
Function Sending10MessagesWasNotAborted(aParentHandle) : Boolean;
Var
i : Integer;
Begin
for i := 0 to 9 do
if ExternalAbort then
break
else begin
SendMessage(ParentHandle, CM_STATUS, Integer(PChar('Durchlauf:')), i);
Sleep(500);
end;
Result := ExternalAbort;
End;
Procedure TryHardToSendMessages (aParentHandle : THandle);
begin
If Sending10MessagesWasNotAborted(aParentHandle) Then
SendMessage(ParentHandle, CM_FINISHED, 0, 0)
else
SendMessage(ParentHandle, CM_ABORT, 0 , 0);
end;
Das ist -finde ich- noch lesbarer.
Nachteil der 2.Variante bzw. des dort verwendeten Verfahrens: Wenn dieses Paradigma durchgezogen wird, entstehen schnell verschachtelte und unleserliche If-Then-Abläufe, z.B.:
Delphi-Quellcode:
..
If Action1IsSuccessfull then
If Action2IsSuccessfull then
If Action3IsSuccessfull then
DoSomething
else
HandleException
else
HandleException
else
HandleException
..
Dann lieber so (Try-Except-Paradigma)
Delphi-Quellcode:
...
Try
Action1;
Action2;
Action3;
Except
HandleException;
End;
Paradigmen sollten zwar stringent durchgezogen werden, aber wozu sind solche Regeln da, wenn nicht zum brechen?