2015-03-04 12 views
8

Angenommen, ich habe die folgende Routine:Delphi - Was ist die "richtige" Reihenfolge für außer und schließlich Blöcke?

function ReadFile(f : TFilename) : Boolean; 
var 
    fs : TFileStream; 
begin 
    Result := False; 
    try 
    fs := TFileStream.Create(f, ...); 
    try 
     // read file ... 
     Result := True; 
    finally 
     FreeAndNil(fs); 
    end; 
    except 
    // handle exceptions ... 
    end; 
end; 

Was sind die Auswirkungen der except und finally umgesetzt haben? Ich habe viele Beiträge mit ihnen in beide Richtungen gesehen, aber ich habe keine klare Erklärung davon gesehen, was in welchen Fällen angemessen ist (ich denke immer noch, es ist seltsam, dass in dem obigen Konstrukt der finally Block nach die except ausführt Block!).

Ich habe auch Beiträge gesehen, die darauf hindeuten, dass Mischen try..except und try..finally Blöcke ist keine gute Idee. Wie können Sie es in Situationen vermeiden, in denen eine Routine eine Ausnahme als Teil der normalen Operation auslöst - wie in einigen der Indy-Routinen?

+3

* "im obigen Konstrukt wird der finally Block nach dem except Block ausgeführt" * - Das ist nicht korrekt. –

Antwort

11

Es gibt keinen einzigen richtigen Weg, dies zu schreiben. Die zwei Varianten machen verschiedene Dinge. Möglicherweise bevorzugen Sie eine Version in einem Szenario, die andere in einem anderen Szenario.

Version 1, schließlich am weitesten innen

function ReadFile(f : TFilename) : Boolean; 
var 
    fs : TFileStream; 
begin 
    Result := False; 
    try 
    fs := TFileStream.Create(f, ...); 
    try 
     // read file ... 
     Result := True; 
    finally 
     FreeAndNil(fs); 
    end; 
    except 
    // handle exceptions ... 
    end; 
end; 

Version 2 schließlich am weitesten außen

function ReadFile(f : TFilename) : Boolean; 
var 
    fs : TFileStream; 
begin 
    Result := False; 
    fs := TFileStream.Create(f, ...); 
    try 
    try 
     // read file ... 
     Result := True; 
    except 
     // handle exceptions ... 
    end; 
    finally 
    FreeAndNil(fs); 
    end; 
end; 

Der große Unterschied ist, wie der Code verhält, wenn TFileStream.Create eine Ausnahme auslöst, eine alles andere als unplausible Eventualität. In Version 1 wird die Ausnahme abgefangen und in ReadFile behandelt. In Version 2 wird die Ausnahme aus ReadFile und in der Kette der Ausnahmebehandler übergeben.

Asides

Sie Zustand:

Ich denke immer noch, dass in dem obigen Konstrukt neugierig ist, führt der finally-Block nach dem außer Block!

Das ist nicht wahr für den Code in Ihrer Frage, Version 1 oben. Vielleicht verstehen Sie noch nicht ganz, wie endlich und Blöcke funktionieren.

Ein häufiger Fehler, der oft beobachtet wird, ist der Wunsch, Ausnahmen so schnell wie möglich zu erfassen und zu behandeln. Das ist die falsche Strategie. Der ganze Punkt über eine Ausnahme ist, dass es nicht passieren soll und Sie normalerweise nicht wissen, was zu tun ist, wenn es passiert. Ihr Ziel ist es, Ausnahmen so spät wie möglich zu behandeln. Für die überwiegende Mehrheit des Codes sollten Sie Ausnahmen nicht behandeln. Lassen Sie sie bis zu einem Punkt im Code aufschwimmen, der mit dem Fehler umgehen kann.

+0

Ok, ich denke ich liege falsch in der Reihenfolge der Ausführung. Ich war mir sicher, dass ich es getestet hatte, indem ich eine Routine durchging, während es eine gefangene Ausnahme behandelte, aber ich denke nicht. Danke für deine Antwort. Schön und gründlich. – rossmcm