В delphi 7 "try ... except raise; end;" вообще имеет смысл?

в некотором коде Delphi 7, который я поддерживаю, я заметил много экземпляров следующего:

with ADOQuery1 do begin
  // .. fill out sql.text, etc
  try
    execSQL;
  except
    raise;
  end;
end;

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

может ли кто-нибудь подумать о каких-либо случаях, когда эти блоки действительно могли бы сделать что-то, что не произошло бы без них?

8 ответов


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

try
  someOperation;
except
  on e: ECustomException do
    SomeCustomHandelr;
  else
     begin
       // the raise is only useful to rethrow the exception to an encompasing 
       // handler.  In this case after I have called my logger code. as Rob
       // mentioned this can be omitted if you arent handling anything because
       // the compiler will simply jump you to the next block if there is no
       // else.
       LogUnexpectedException('some operation failed',e);
       raise;
     end;
end;

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

with ADOQuery1 do begin  
  // .. fill out sql.text, etc  
  try    
    execSQL; 
  except
    // no handler so this just eats any "errors"    
  end;

удаление кода except в приведенном выше фрагменте кода не будет иметь никакого значения. Вы можете (и я верю вам должны так как это уменьшает читаемость) удалите его.


хорошо, здесь действительно два вопроса.

во-первых, это is meaningful: если execSQL выдает исключение, оно перехватывается блоком try и перенаправляется в except. Затем он переадресовывается повышением в следующий более высокий блок.

во-вторых, это полезное? Скорее всего, нет. Почти наверняка это результат одной из трех вещей:--2-->

  1. кто-то с заостренными волосами написал стандарт кодирования, который сказал: "Все операции, которые могут исключение должно быть в блоке try."
  2. кто-то хотел вернуться и повернуть исключения сделаны execSQL заявление в какое-то другое, более значимое, исключение.
  3. кто-то новый не знал, что то, что они написали, было изоморфным, чтобы позволить среде uter беспокоиться об исключении, и поэтому они думали, что должны вперед.

возможно, я ответил Слишком быстро, см. В конце...
как это, это бесполезно для приложения.
Точка!

Теперь на стороне "почему". Это может быть стандартизация обработки исключений, если есть /был/будет/ есть в других местах / какой-то код журнала, вставленный перед повышением:

  try
    execSQL;
  except
    // Log Exception..
    on E: Exception do
    begin
      LogTrace(Format('%s: Exception Message[%s]',[methodname, E.Message]));
      raise;
    end;
  end;

или для подчистки кода:

  try
    execSQL;
  except
    //some FreeAndNil..
    raise;
  end;

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


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


на самом деле, я должен опубликовать это как комментарий к ответам Франсуа, но я не знаю, можно ли вставить форматированный код там :( поэтому я публикую это как ответ.

2mghie:

второй полностью unidiomatic, один будет использовать, наконец, вместо этого.

нет, "finally"всегда будет объектом очистки. "Кроме" - только на исключение. Рассмотрим случай функции, которая создает, заполняет и возвращает объект:

function CreateObj: TSomeObj;
begin
  Result := TSomeObj.Create;
  try
    ... // do something with Result: load data, fill props, etc.
  except
    FreeAndNil(Result); // oops: bad things happened. Free object to avoid leak.
    raise;
  end;
end;

Если вы поставите "finally" там-функция всегда будет возвращать ноль. Если вы вообще опустите блок "try" - произойдет утечка ресурсов в случае исключения в "...".

P. S. Конечно, вы можете использовать "наконец-то" и проверить ExceptObj, но... разве это не отвратительно?


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

а, может быть Blorgbeard действительно хочет знать, является ли это на всех смысл try ... except raise; end. В Delphi 7, Если я правильно помню, Exit автоматически finally часть try-finally блок (как если бы это было какое-то исключение). Кто-то может считать такое поведение неуместным для своей задачи, и использование рассматриваемой конструкции является довольно обходным путем.

только это все равно было бы странно использовать один raise; есть, но тогда мы должны были поговорить о полезность, а не осмысленности, как аккуратно заметил Чарли.


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