28

サンプルとして次のコードを取ります。

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は、これらの行に到達する前にコードが壊れていたため、砂時計としてスタックしたままになりますか?

誤解しない限り、次のようなエラーの発生に対処するために、例外ステートメントを配置する必要があります。

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ブロックとafter、およびExceptionブロックに同じコードを2回含める理由はないはずです。

基本的に、私が投稿した最初のサンプルに似た手順がある場合があります。エラーが発生した場合、カーソルは砂時計として動かなくなります。Exceptionハンドラーを追加すると役立ちますが、それを行うには汚い方法のようです。FinallyからExceptionの部分にコピーアンドペーストする醜いコードは言うまでもなく、基本的にFinallyブロックを無視します。

私はまだDelphiを非常に学んでいるので、これが簡単な質問/回答であると思われる場合はお詫びします。

ステートメントを処理し、オブジェクトを正しく解放し、エラーなどをキャプチャするために、コードをどのように正しく記述する必要がありますか?

4

7 に答える 7

38

必要なのは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何が起こっても、セクションのコードは実行されることが保証されます。tryfinally

したがって、上記のコードでは、外部は例外が発生した場合に復元されるtry/finallyことを保証します。Screen.Cursor同様に、内部は、その存続期間中に例外が発生した場合に、try/finallyそれが破棄されることを保証します。Obj


例外を処理する場合は、個別のtry/exceptブロックが必要です。ただし、ほとんどの場合、例外の処理を試みるべきではありません。ユーザーにメッセージを表示するメインアプリケーションの例外ハンドラーまで伝播させてください。

例外を処理してコールチェーンをローダウンすると、呼び出し元のコードは、呼び出したコードが失敗したことを認識しません。

于 2011-07-06T18:25:05.213 に答える
18

元のコードは思ったほど悪くはありません(ただし、悪いです)。

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 あなたが何が起こっても実行されます// do something。例外が発生した場合でも(以降try)、finallyブロック実行されます!それが構成の要点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;
于 2011-07-06T18:26:44.367 に答える
16

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の参照カウントインターフェイスメカニズムは、カーソルの復元を処理します。

于 2011-07-06T19:03:29.030 に答える
6

最も「正しい」バージョンはこれだと思います:

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;
于 2011-07-07T09:13:04.393 に答える
2

例外を処理し、アプリを強制終了しない必要があるサービス/サーバーで多くのコードを実行した後、私は通常、次のようなものを探します。

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が常に破壊されることを確認します...

于 2011-07-07T10:27:59.543 に答える
2

私はこのようにします:

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;
于 2014-08-06T06:21:54.997 に答える
1

try-except-finallyここで自分の道を見つけ、DelphiでC#から構成を作成する方法を探していた場合:

// C#
try
{
    // Do something
}
catch
{
    // Exception!
}
finally
{
    // Always do this...
}

答えは、これを直接行うことはできないということです。代わりに、@ sacconagoが示唆するようにtry、次のようにブロックをネストします。

// Delphi
try
    try
        // Do something
    except
        // Exception!
    end;
finally
    // Always do this...
end;

Delphiの優れた機能の1つは、ブロックをtry...except...finallyまたはとしてネストできることですがtry...finally...except、前者の方が一般的です。

于 2021-07-18T22:49:32.547 に答える