Считается ли это плохой практикой или существует какой-либо недостаток, использующий try / finally try / кроме вместо begin / end? - PullRequest
2 голосов
/ 31 января 2012

Во многих местах в некоторых приложениях, которые я поддерживаю, я нашел код, который использует блок try/finally или try/except в предложении for loop или if, избегая использования начала / конца

Рассмотрим следующий код (не производственный код, просто пример)

{$APPTYPE CONSOLE}

{$R *.res}

uses
  Classes,
  SysUtils;

Procedure TestNoBeginEnd;
var
 i   : Integer;
 L1  : TStringList;
begin
    for i := 1 to 10 do
    try
      L1:=TStringList.Create;
      try
        L1.Add('Bar');
        L1.Add(IntToStr(i));
        L1.Add('Foo');
      finally
        Writeln(L1.Text);
        L1.Free;
      end;
    except
      on E: Exception do
        Writeln('Opps '+E.ClassName, ': ', E.Message);
    end;
end;

begin
  try
    TestNoBeginEnd;

  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  Readln;
end.

Вопрос, Считается ли это плохой практикой, запаха кода или существует какой-либо недостаток, используя вместо этого попытку / окончание или попытку / кроменачало / конец в delphi?

ОБНОВЛЕНИЕ

Извините за глупый пример кода, только для пояснения try / finally и try / кроме не претендуетзамените начало / конец, просто чтобы избежать его использования (начало / конец), когда существует случай, когда использование try / finally или try / кроме не требует начала / конца.

Ответы [ 4 ]

6 голосов
/ 31 января 2012

Лично я не вижу необходимости добавлять дополнительные begin..end вокруг try..finally/except..end, особенно когда существует небольшая вероятность добавления кода непосредственно перед try или, конечно, после end.

При этом возникает вопрос: нужно ли нам систематически begin..end после ..do или ..then, даже если есть только одна инструкция (в вашем случае try.. инструкция).

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

Когда задействовано значительное количество строк, я склоняюсь к добавлению begin..end, чтобы сделать обзор более очевидным.

Я бы сказал, используйте здравый смысл и посмотрите, какова вероятность того, что кто-то (или вы), изменяющий код позже, может пропустить предполагаемую область.

1 голос
/ 31 января 2012

Ваше изменение вопроса радикально изменило вопрос.Вы должны были как минимум изменить заголовок, и сейчас мне интересно, можно ли вообще восстановить этот вопрос (-1).

При ответе на ваш первоначальный вопрос:

A Попробуйте /Наконец, оператор Try / Except никогда не должен использоваться, когда достаточно оператора Begin / End.Помимо того, что операторы Try добавляют (крошечные или даже незаметные) дополнительные инструкции к скомпилированному коду, они подразумевают необходимость кода, которого там нет:

for I := 0 to Count - 1 do
try
  Inc(Rect.Left, Shift);
finally
  Inc(Rect.Right, Shift);
end;

Просто не делайте этого.

1 голос
/ 31 января 2012

обо всем по порядку. Начало / Конец не совпадает с Try / Etc Последний первый обозначает набор инструкций, а второй представляет собой одну инструкцию (которая может содержать много инструкций).

Так они как молоток и лестница. Разные инструменты для разных работа. Конечно, ты забиваешь ноготь с лестницей, но это не самое эффективный способ решения проблемы.

Edit: Если я возьму вопрос (теперь, когда вы его отредактируете), вы спросите, можно ли использовать одну попытку / etc без начала / конца. Да, вы можете сделать это, потому что try / etc - это одно утверждение. На самом деле, я бы сказал, что это хорошая вещь - избегать слишком много бесполезного кода.

Перед редактированием:

Так что это значит? Ну, это означает, что если в этой функции происходит ошибка, она регистрируется, но по существу игнорируется.

Если нет действительно хорошей обработки исключений , а код эскалирует исключения или восстанавливается правильно Я бы сказал, что это плохая практика .

В вашем примере все, что делает обработчик исключений, это сказать Opps (упс?). Что в этом хорошего? Конечно, это всего лишь пример, и поэтому я изучу код, чтобы увидеть, что он на самом деле делает. Я полагаю, что человек, который написал это, пытался обрабатывать ошибки в целом, но на самом деле надежность кода намного ухудшается при использовании этого шаблона.

Я использую общий случай «Обработчики исключений предназначены для исключительных обстоятельств» , где я могу прийти в себя или мне нужно сообщить кому-то / предмету. В основном я считаю, что никто не может справиться с ошибкой, и система должна ухудшиться в соответствии с проектом. Именно здесь обработчики исключений будут безопасно регистрироваться и передавать исключения.

В последнем случае я распространяюсь на все «большие границы в системе». т.е. я буду собирать исключения на границах Service / API и регистрировать / оборачивать соответствующим образом.

(обратите внимание, что иногда плохие API-интерфейсы используют исключения для неисключительных обстоятельств, в этом случае вы можете безопасно добавить обработчик исключений, чтобы обернуть плохой дизайн).

0 голосов
/ 31 января 2012

Нет ничего плохого в том, чтобы пропустить начало конца, когда попытка окончить / исключает завершение одного и того же кода в блок для вас. Просто помните, что у блоков try больше издержек, чем у блока begin. Эти издержки, как правило, незначительны, но я обнаружил, что они имеют существенные отличия, когда используются циклы, особенно циклы в методах, на которые ссылаются неоднократно.

Учитывая вышеперечисленные детали, ваш пример несколько плох из-за того, что он постоянно добавляет ненужные накладные расходы в цикл. Всякий раз, когда вы можете переместить блоки из цикла, это хорошо. В вашем примере, если вы ДОЛЖНЫ иметь возможность перехватывать исключение для каждой итерации цикла, приведенный ниже код будет более эффективным, если нет, то также переместите блок исключений.

Procedure TestNoBeginEnd;
var
 i   : Integer;
 L1  : TStringList;
begin
  L1:=TStringList.Create;
  try
    for i := 1 to 10 do
    try
      L1.Clear;
      L1.Add('Bar');
      L1.Add(IntToStr(i));
      L1.Add('Foo');
      Writeln(L1.Text);
      end;
    except
      on E: Exception do
        Writeln('Opps '+E.ClassName, ': ', E.Message);
    end;
  finally
    L1.Free;
  end;
end;
...