В delphi 7 это `попробуй ... кроме рейза; конец; `значащий вообще? - PullRequest
7 голосов
/ 30 апреля 2009

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

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

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

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

Ответы [ 8 ]

10 голосов
/ 30 апреля 2009

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

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;
6 голосов
/ 30 апреля 2009

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

2 голосов
/ 30 апреля 2009

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

2 голосов
/ 30 апреля 2009

Возможно, я ответил немного быстро, смотри в конце ...
Вроде бы бесполезно для приложения .
Период!

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

  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, чтобы получить возможность увидеть, что происходит в контексте этого блока кода.

2 голосов
/ 30 апреля 2009

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

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

Во-вторых, это полезно ? Возможно нет. Это почти наверняка является результатом одной из трех вещей:

  1. Кто-то с заостренными волосами написал стандарт кодирования, который гласил, что «все операции, которые могут вызвать исключение, должны быть в блоке try».
  2. Кто-то хотел вернуться и превратить исключения, сделанные в уставе execSQL, в другое, более значимое исключение.
  3. Кто-то новичок не знал, что написанное им было изоморфно тому, чтобы окружающая среда беспокоилась об исключении, и поэтому подумал, что должен переслать его.
1 голос
/ 30 апреля 2009

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

2mghie:

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

Нет, "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" - функция всегда будет возвращать nil. Если вы вообще пропустите блок try - в случае исключения в «...» произойдет утечка ресурсов.

P.S. Конечно, вы можете использовать «finally» и проверить ExceptObj, но ... разве это не уродливо?

0 голосов
/ 30 апреля 2009

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

0 голосов
/ 30 апреля 2009

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

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

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

...