Delphi - Какой "правильный" порядок для блоков исключений и окончательно?

Предположим, у меня есть следующая процедура:

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;

Каковы последствия наличия except а также finally транспонированная? Я видел множество постов с ними обоими способами, но я не видел четкого объяснения того, что уместно в каких случаях (я все еще думаю, что любопытно, что в вышеупомянутой конструкции, finally блок выполняется после except блок!).

Я также видел посты, которые предполагают, что смешивание try..except а также try..finally блоки не очень хорошая идея. Как вы можете избежать этого в ситуациях, когда процедура вызывает исключение как часть нормальной работы, например, в некоторых процедурах Indy?

1 ответ

Решение

Нет единственно правильного способа написать это. Два варианта делают разные вещи. Вы можете предпочесть одну версию в одном сценарии, а другую - в другом.

Версия 1, наконец, самая внутренняя

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;

Версия 2, наконец, самая внешняя

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;

Большая разница в том, как код ведет себя, если TFileStream.Create Возникает исключение, далеко не правдоподобное событие. В версии 1 исключение будет поймано и обработано внутри ReadFile, В версии 2 исключение будет передано из ReadFile и вверх по цепочке обработчиков исключений.

Asides

Вы заявляете:

Я все еще думаю, что любопытно, что в приведенной выше конструкции блок finally выполняется после блока исключений!

Это не относится к коду в вашем вопросе, версия 1 выше. Возможно, вы еще не до конца понимаете, как в конечном итоге работают блоки.

Распространенная ошибка, которая часто наблюдается, - это желание отлавливать и обрабатывать исключения как можно скорее. Это неправильная стратегия. Весь смысл исключения состоит в том, что оно не должно происходить, и вы обычно не знаете, что делать, когда это произойдет. Ваша цель - обрабатывать исключения как можно позже. Для подавляющего большинства кода вы просто не должны обрабатывать исключения. Пусть они всплывают вверх в той точке кода, которая способна справиться с ошибкой.

Другие вопросы по тегам