サンプルとして次のコードを使用します。
procedure TForm1.Button1Click(Sender: TObject);
var
Obj: TSomeObject;
begin
Screen.Cursor:= crHourGlass;
Obj:= TSomeObject.Create;
try
// do something
finally
Obj.Free;
end;
Screen.Cursor:= crDefault;
end;
// do something
セクションでエラーが発生した場合、作成されたと思われるTSomeObjectは解放されず、Screen.Cursorは砂時計のままになります。これらの行に到達する前にコードが壊れたためです?
誤解しない限り、次のようなエラーの発生に対処するために、Exceptionステートメントを配置する必要があります。
procedure TForm1.Button1Click(Sender: TObject);
var
Obj: TSomeObject;
begin
try
Screen.Cursor:= crHourGlass;
Obj:= TSomeObject.Create;
try
// do something
finally
Obj.Free;
end;
Screen.Cursor:= crDefault;
except on E: Exception do
begin
Obj.Free;
Screen.Cursor:= crDefault;
ShowMessage('There was an error: ' + E.Message);
end;
end;
今、私が本当に愚かなことをしていない限り、Finallyブロックとその後、そしてExceptionブロックで同じコードを2回持つ理由はないはずです。
基本的に、最初に投稿したサンプルに似た手順がいくつかあり、エラーが発生した場合はカーソルが砂時計としてスタックしています。例外ハンドラーを追加することは役立ちますが、それを行うのは汚い方法のようです-基本的に、Finallyブロックを無視します。
私はまだDelphiを非常に学んでいるので、これが簡単な質問/回答であると思われる場合は謝罪します。
ステートメントを処理し、オブジェクトを正しく解放し、エラーをキャプチャするために、どのようにコードを正しく記述する必要がありますか?
必要なのは2つのtry/finally
ブロック:
Screen.Cursor:= crHourGlass;
try
Obj:= TSomeObject.Create;
try
// do something
finally
Obj.Free;
end;
finally
Screen.Cursor:= crDefault;
end;
従うべきガイドラインは、リソースを保護するためにfinally
ではなくexcept
を使用することです。あなたが観察したように、except
でそれを行おうとすると、ファイナライズコードを2回書くことを余儀なくされます。
try/finally
ブロックでは、finally
とtry
の間で何が起こっても、finally
セクションのコードの実行が保証されます。
したがって、上記のコードでは、外側のtry/finally
はScreen.Cursor
は、例外が発生した場合に復元されます。同様に、内側のtry/finally
は、そのライフタイム中に例外が発生した場合にObj
が確実に破棄されるようにします。
例外を処理する場合は、_try/except
ブロック。ただし、ほとんどの場合、not例外の処理を試みる必要があります。ユーザーにメッセージを表示するメインアプリケーション例外ハンドラーまで伝播させるだけです。
例外を処理して呼び出しチェーンを低くすると、呼び出し元のコードは、呼び出したコードが失敗したことを知りません。
元のコードは思ったほど悪くはありません:
procedure TForm1.Button1Click(Sender: TObject);
var
Obj: TSomeObject;
begin
Screen.Cursor := crHourGlass;
Obj := TSomeObject.Create;
try
// do something
finally
Obj.Free;
end;
Screen.Cursor := crDefault;
end;
Obj.Free
will// do something
のときに何が起きても実行されます。例外が発生した場合(try
の後)、finally
ブロックwillが実行されます!これがtry..finally
コンストラクトのポイントです!
ただし、カーソルも復元する必要があります。最も用心深い方法は、2つのtry..finally
コンストラクトを使用することです。
procedure TForm1.Button1Click(Sender: TObject);
var
Obj: TSomeObject;
begin
Screen.Cursor := crHourGlass;
try
Obj := TSomeObject.Create;
try
// do something
finally
Obj.Free;
end;
finally
Screen.Cursor := crDefault;
end;
end;
[しかし、私も気にしない
procedure TForm1.Button1Click(Sender: TObject);
var
Obj: TSomeObject;
begin
Obj := TSomeObject.Create;
Screen.Cursor := crHourGlass;
try
// do something
finally
Screen.Cursor := crDefault;
Obj.Free;
end;
end;
過度に。 Screen.Cursor := crHourGlass
が失敗するリスクはかなり低いですが、そのような場合、オブジェクトは解放されません(finally
の中にいないため、try
は実行されません)。二重のtry..finally
の方が安全です。]
他の人が説明したように、try finally
ブロックでカーソルの変更を保護する必要があります。これらの記述を避けるために、次のようなコードを使用します。
unit autoCursor;
interface
uses Controls;
type
ICursor = interface(IInterface)
['{F5B4EB9C-6B74-42A3-B3DC-5068CCCBDA7A}']
end;
function __SetCursor(const aCursor: TCursor): ICursor;
implementation
uses Forms;
type
TAutoCursor = class(TInterfacedObject, ICursor)
private
FCursor: TCursor;
public
constructor Create(const aCursor: TCursor);
destructor Destroy; override;
end;
{ TAutoCursor }
constructor TAutoCursor.Create(const aCursor: TCursor);
begin
inherited Create;
FCursor := Screen.Cursor;
Screen.Cursor := aCursor;
end;
destructor TAutoCursor.Destroy;
begin
Screen.Cursor := FCursor;
inherited;
end;
function __SetCursor(const aCursor: TCursor): ICursor;
begin
Result := TAutoCursor.Create(aCursor);
end;
end.
今、あなたはそれを次のように使用します
uses
autoCursor;
procedure TForm1.Button1Click(Sender: TObject);
var
Obj: TSomeObject;
begin
__SetCursor(crHourGlass);
Obj:= TSomeObject.Create;
try
// do something
finally
Obj.Free;
end;
end;
delphiの参照カウントインターフェイスメカニズムは、カーソルの復元を処理します。
私はこのようにします:
var
savedCursor: TCursor;
Obj: TSomeObject;
begin
savedCursor := Screen.Cursor;
Screen.Cursor := crHourGlass;
Obj:= TSomeObject.Create;
try
try
// do something
except
// record the exception
end;
finally
if Assigned(Obj) then
Obj.Free;
Screen.Cursor := savedCursor;
end;
end;
例外を処理し、アプリを殺さないようにする必要があるサービス/サーバーで多くのコードを実行した後、私は通常次のようなものを探します:
procedure TForm1.Button1Click(Sender: TObject);
var
Obj: TSomeObject;
begin
try
Obj := NIL;
try
Screen.Cursor := crHourGlass;
Obj := TSomeObject.Create;
// do something
finally
Screen.Cursor := crDefault;
if assigned(Obj) then FreeAndNil(Obj);
end;
except
On E: Exception do ; // Log the exception
end;
end;
最後に試してみてください。トライを除いておよびObj作成の配置。
objがコンストラクター内で他のものを作成する場合、途中で動作し、.create()内で例外が発生して失敗する場合があります。それでも作成されたObjである。そのため、Objが割り当てられている場合は常に破棄されるようにします...
最も「正しい」バージョンはこれだと思います:
procedure TForm1.Button1Click(Sender: TObject);
var
Obj: TSomeObject;
begin
Obj := NIL;
Screen.Cursor := crHourGlass;
try
Obj := TSomeObject.Create;
// do something
finally
Screen.Cursor := crDefault;
Obj.Free;
end;
end;