Является ли выражение Delphi Exit опасным? - программирование
Подтвердить что ты не робот

Является ли выражение Delphi Exit опасным?

Чтение о заявлении Delphi Exit (см. здесь), я не могу игнорировать это письмо об этом, каждый автор считает обязанностью давать совет, например:

Предупреждение: используйте с осторожностью - прыжки - это концепция, противоречащая структурированному кодированию - это затрудняет обслуживание кода.

Теперь я прихожу из C и С++ в Unix, и я знаком с проблемами повторного входа, но, честно говоря, я не могу понять, почему в Delphi, возвращающемся из функции до того, как она достигает своего естественного конца, должно быть злым.

Если каждая функция и процедура в Delphi не рассматриваются как повторные.

Что мне не хватает?

4b9b3361

Ответ 1

Есть две школы мысли.

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

Другая школа мысли говорит, что код спагетти плох, но нужно быть прагматичным и судить о стилях кодирования по существу, а не следовать догматическим правилам. Например, многие программисты считают, что фразы охраны гораздо предпочтительнее функций с глубоким отступом, возникающих, когда вы воздерживаетесь от использования exit. В качестве иллюстрации рассмотрим следующий пример от Мартина Фаулера, отличный каталог рефакторинга: Заменить вложенные условные условия с защитными оговорками.

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

Ответ 2

Вам не хватает, что он не говорит "не используйте это" или "Выход - это зло"; он говорит: "Используйте его осторожно". И в нем говорится, что это может затруднить техническое обслуживание. Например, если у вас есть большой метод и там есть такая строка где-то посередине, вы можете пропустить это полностью:

if aLocalObject.CheckSomeValue(aParameter) <> RIGHT_VALUE then Exit;

И, к сожалению, я действительно видел такие вещи раньше.: (

Многие проблемы могут быть смягчены с помощью нескольких эмпирических правил:

  • Всегда помещайте выражения ExitBreak и Continue) в свою собственную строку. Это затрудняет их пропустить.
  • Благоприятные методы по сравнению с более крупными и разлагайте большие методы на более мелкие, когда это разумно. (КОГДА УЛУЧШЕНО! Это не абсолютное правило, и применение этого слишком усердно может ухудшить ситуацию, а не лучше. Держите Эйнштейна в уме: "Сделайте все как можно проще, но не проще".)
  • Научитесь использовать блоки try/finally, чтобы Exit выйти из процедуры безопасно обойтись без утечек или повреждения.

Ответ 3

В дополнение к превосходным ответам Дэвида и Мейсона я хотел бы поделиться своим личным любимым любимым Exit. Позвольте называть его, совершенно противоположным "безопасному охраннику", "последним провайдером".;)

Основная идея:

function Search(List: TList; Item: TObject): Integer;
begin
  for Result := 0 to List.Count - 1 do
    if List[Result] = Item then
      Exit;
  Result := -1;
end;

Другие более реалистичные примеры (от этого ответа и этот ответ):

const 
  Order: array[0..6] of String = ('B', 'C', 'A', 'D', 'G', 'F', 'E'); 

function GetStringOrder(const S: String; CaseSensitive: Boolean): Integer; 
begin 
  for Result := 0 to Length(Order) - 1 do 
    if (CaseSensitive and (CompareStr(Order[Result], S) = 0)) or 
        (not CaseSensitive and (CompareText(Order[Result], S) = 0)) then 
      Exit; 
  Result := Length(Order); 
end; 

function FindControlAtPos(Window: TWinControl; const ScreenPos: TPoint): TControl; 
var 
  I: Integer; 
  C: TControl; 
begin 
  for I := Window.ControlCount - 1 downto 0 do 
  begin 
    C := Window.Controls[I]; 
    if C.Visible and PtInRect(C.ClientRect, C.ScreenToClient(ScreenPos)) then 
    begin 
      if C is TWinControl then 
        Result := FindControlAtPos(TWinControl(C), ScreenPos) 
      else 
        Result := C; 
      Exit; 
    end; 
  end; 
  Result := Window; 
end; 

И заключение с цитатой из справки Delphi о сообщении об ошибке компилятора. FOR-Loop переменная '<element> ' может быть undefined после цикла:

Вы можете полагаться только на конечное значение переменной управления циклом for, если цикл остается с оператором goto или exit.

Ответ 4

Как и многие вещи, выход полезен в некоторых случаях, а не в других. Я нахожу это неоценимым в тех маленьких функциях, которые ищут через какой-то контейнер, загружая объект из контейнера в "результат" внутри цикла и ищет подходящее свойство. Если найдено, функция может просто выйти, если нет, результат может быть установлен на нуль после цикла, как раз перед возвратом "нормального".

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

Я могу только согласиться с вопросами, поднятыми другими плакатами re. защитные оговорки, выходы, засыпанные большими, сложными процедурами и т.д.