ДОПОЛНИТЕЛЬНАЯ РАЗЪЯСНЕНИЕ: Как правильно написать операторы Try..Finally..Except?

delphi try-finally try-except

1023 просмотра

3 ответа

9 Репутация автора

RE: Как правильно написать Try..Finally..Except операторов?

Я все еще смущен оригинальным вопросом ОП. В частности, последняя строка процедуры (за пределами try..finally..end), которая гласит «Screen.Cursor: = crDefault».

Я понимаю, что любые исключения поднятые внутри try..except | finally..end блок БУДЕТ выполнять код после «конца» «попробовать».

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;

В приведенном выше примере я не вижу причин, по которым «Screen.Cursor: = crDefault» не будет выполнен. Пожалуйста, поправьте меня, если я ошибаюсь.

В качестве дальнейшего примера я скомпилировал этот небольшой кусочек кода, чтобы помочь проиллюстрировать. Когда код будет запущен, будут представлены три (3) диалога ShowMessage (). Первое «Возникло исключение», второе «наконец» и третье «в конце».

procedure TForm1.Button1Click(Sender: TObject);
begin
   try
      try
         showMessage(format('%s', [12]));
      except
         showMessage('Exception raised');
      end;
   finally
      showMessage('finally');
   end;
   showMessage('at end');
end;

Итак, я запутался, почему его «Screen.Cursor: = crDefault» не запускается, в его оригинальной форме и коде. Может кто-нибудь уточнить, пожалуйста?

Автор: Vin Colgin Источник Размещён: 21.11.2013 07:55

Ответы (3)


1 плюс

8108 Репутация автора

Вы на самом деле не поймать исключение. В этом случае при исключении будет выполнен блок кода finally, а затем исключение размотает стек.

Автор: DarkWanderer Размещён: 21.11.2013 08:02

11 плюса

110853 Репутация автора

Код, который вы разместили, кажется, работает нормально, потому что вы можете использовать все возможности. Попробуйте хотя бы немного его изменить, чтобы исключение не возникло в вашем коде:

procedure TForm1.Button1Click(Sender: TObject);
begin
  try
    try
      raise Exception.Create('42');
    except
      on E: EDivByZero do
        ShowMessage('DivByZero');
    end;
  finally
    ShowMessage('Finally');
  end;
  ShowMessage('Got here');
end;

Запустите это, и вы увидите Finally, затем исключение для 42, но без Got hereсообщения. Это связано с тем, что исключение вывело вас из текущего блока, стек был размотан, а код от endпроцедуры finally до конца процедуры никогда не выполняется.

Переместите последний ShowMessageвызов изнутри finallyи выполните снова.

procedure TForm1.Button1Click(Sender: TObject);
begin
  try
    try
      raise Exception.Create('42');
    except
      on E: EDivByZero do
        ShowMessage('DivByZero');
    end;
  finally
    ShowMessage('Finally');
    ShowMessage('Got here');
  end;
  ShowMessage('Will never get here');
end;

Теперь вы увидите оба вызова ShowMessageв finallyблоке, один за другим, но не один после finallyблока end;. Код внутри finallyблока гарантированно выполняется, а код за его пределами может или не может.

Чтобы было еще понятнее, наличие try..exceptблока можно убрать:

procedure TForm1.Button1Click(Sender: TObject);
begin
  try
    raise Exception.Create('42');
  finally
    ShowMessage('Finally');
    ShowMessage('Got here');
  end;
  ShowMessage('Will never get here');
end;

Вся цель try..finallyблока состоит в том, чтобы гарантировать, что код внутри finallyсекции будет выполняться до завершения процедуры.

Автор: Ken White Размещён: 21.11.2013 08:08

1 плюс

171 Репутация автора

В Delphi finallyблок на самом деле не обрабатывает исключение, которое произошло в tryблоке. Это только гарантирует, что код в finallyблоке будет всегда выполняться независимо от того, произошло исключение или нет в tryблоке. Если там действительно произошло исключение, оно не будет поймано. И когда исключение не было обнаружено, вы знаете, что случилось с кодом ниже.

Чтобы поймать исключение, которое может произойти, используйте try...except...вместо этого блок. Вы можете объединить эти две конструкции для выполнения этих двух действий: (1) гарантировать выполнение некоторого фрагмента кода и (2) перехватывать исключения, которые могут произойти. Обычное использование выглядит так:

try
  try
    // do something that might cause an exception.
  finally
    // do something that must be executed WHATEVER happened.
  end;
except
  // do something ONLY IF an exception has occured.
end;

Итак, вы должны изменить свой код и переместить Screen.Cursor := crDefault;внутрь finallyблока. Кроме того, добавьте try...except...блок, чтобы окружить try...finally...блок. Нравится:

procedure TForm1.Button1Click(Sender: TObject);
var
  Obj: TSomeObject;
begin
  Screen.Cursor := crHourGlass;
  Obj := TSomeObject.Create;
  try
    try
      // do something.
    finally
      Obj.Free;
      Screen.Cursor := crDefault;
    end;
  except
    ShowMessage('An error has occured!');
  end;
end;

Или, если вы не уверены, что код Obj := TSomeObject.Create;достаточно безопасен, вы должны добавить второй try...finally...блок, чтобы окружить его, например так:

procedure TForm1.Button1Click(Sender: TObject);
var
  Obj: TSomeObject;
begin
  Screen.Cursor := crHourGlass;
  try
    try
      Obj := TSomeObject.Create;
      try
        // do something.
      finally
        Obj.Free;
      end;
    finally
      Screen.Cursor := crDefault;
    end;
  except
    ShowMessage('An error has occured!');
  end;
end;

Там, надеюсь, это помогает :)

Автор: Choerun Asnawi Размещён: 22.11.2013 03:05
Вопросы из категории :
32x32