ДОПОЛНИТЕЛЬНАЯ РАЗЪЯСНЕНИЕ: Как правильно написать операторы Try..Finally..Except?
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" не запускается, в его оригинальной форме и коде. Может кто-нибудь уточнить, пожалуйста?
3 ответа
Код, который вы разместили, кажется, работает нормально, потому что вы можете использовать все возможности. Попробуйте хотя бы немного изменить его, чтобы исключение не возникло в вашем коде:
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
от конца до конца процедура никогда не выполняется.
Переместить финал 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
раздел будет выполнен до завершения процедуры.
В Дельфи 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;
Там, надеюсь, это помогает:)
Вы на самом деле не поймать исключение. В этом случае при исключении будет выполнен блок кода finally, а затем исключение размотает стек.