Как я могу узнать, какие исключения может выдавать функция Delphi?

StackOverflow https://stackoverflow.com/questions/72562

  •  09-06-2019
  •  | 
  •  

Вопрос

Есть ли хороший способ узнать, какие исключения процедура / функция может вызывать в Delphi (включая то, что она называется procedures / functions)?

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

Существуют ли какие-либо инструменты анализа кода, которые обнаруживают необработанные исключения?

Это было полезно?

Решение

(Редактировать:Теперь очевидно, что вопрос касался Только для проверки во время разработки.)

Новый ответ:

Я не могу сказать, есть ли какие-либо инструменты, чтобы проверить это для вас.Анализатор Pascal, например, этого не делает.

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

Почему? Потому что основной цикл обмена сообщениями в TApplication.Run() оборачивает все вызовы handleMessage() в блок обработки исключений, который улавливает все типы исключений.Таким образом, у вас будет неявная обработка исключений по умолчанию примерно в 99,999% кода в большинстве приложений.И в большинстве приложений эта обработка исключений будет составлять около 100% вашего собственного кода - те 0,001% кода, которые не включены в обработку исключений, будут автоматически сгенерированным кодом.

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

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

Другие советы

Я предполагаю, что вы пытаетесь заставить Delphi вести себя как Java, что не является хорошим подходом.Я бы посоветовал не слишком беспокоиться о необработанных исключениях.В худшем случае они всплывут в общий обработчик исключений VCL и вызовут диалоговое окно сообщения Windows.В обычном приложении они не будут останавливать приложение.

Хорошо написанный код документировал бы различные исключения, которые могут быть вызваны, чтобы вы могли обрабатывать их осмысленным образом.Обработчики Catch-all не рекомендуются, поскольку на самом деле нет способа узнать, что делать, если вы не знаете, почему было вызвано исключение.Я также могу настоятельно рекомендовать MadExcept.

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

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

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

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

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

Одна фундаментальная особенность Delphi заключается в том, что исключения являются иерархическими:Все определенные языковые исключения происходят из Исключение, хотя стоит отметить , что на самом деле можно поднять любой Подвергать сомнению потомок.

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

// Other code . . . 
try
  SomeProcedure()
except  // BAD IDEA!
  ShowMessage('I caught them all!');
end;

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

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

Однако вы не хотите использовать это для ВСЕХ исключений, просто чтобы поймать те, которые вы пропустили.Например, если вы открываете базу данных и происходит сбой входа в систему, для вас было бы лучше перехватить и обработать это самостоятельно, а не выдавать пользователю сообщение об ошибке MadExcept по умолчанию в вашем приложении occurred.

Любое исключение, не обработанное явно или вообще на определенном уровне, будет просачиваться вверх по стеку вызовов.Delphi RTL (библиотека времени выполнения) сгенерирует набор различных классов исключений (математические ошибки, ошибки доступа, ошибки, относящиеся к конкретному классу и т.д.).Вы можете обрабатывать их отдельно или вообще в разных блоках try except.

На самом деле вам не нужно объявлять какие-либо новые классы исключений, если только вам не нужно распространять определенный функциональный контекст с исключением.

Как писали предыдущие комментаторы, вы также можете добавить мать всех обработчиков исключений, таких как MadExcept или EurekaLog, чтобы перехватить неперехваченное.

Редактировать:Это полная страховка от необработанных исключений

try
  ThisFunctionMayFail;
except
  // but it sure won't crash the application
  on e:exception
  do begin
    // something sensible to handle the error 
    // or perhaps log and/or display the the generic e.description message
  end
end;

Для выполнения попробуйте Эврекалог.Я не знаю, существует ли инструмент для разработки.У вас будет больше сложностей, даже если у вас есть сторонний код без исходного кода.В Delphi нет необходимости перехватывать исключения, поэтому вам не нужно объявлять их, как в Java.

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

Как указывает Джим Маккит, вы не можете получить окончательный ответ, но мне кажется, что один из них мог бы быть частично ответьте на вопрос с помощью некоторого статического анализа:учитывая конкретную функцию / процедуру, постройте граф вызовов.Проверьте каждую из функций в этом графике вызовов на наличие инструкции raise.Это сообщило бы вам, например, что TIdTCPClient.ReadString может вызывать EIdNotConnected (среди прочих).

Умный анализатор мог бы также заметить, что какой-то код использует оператор / и включает EDivByZero в качестве возможности, или что какая-то процедура обращается к массиву и включает ERangeError .

Этот ответ немного сложнее, чем просто призыв к "повышению".

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

Я думаю, что в Delphi IDE есть встроенная "трассировка стека" или "дерево стека" что-то вроде.

Этот вопрос напоминает мне игру Skybuck's TRussianRoulette...погуглите, это код и ответ могут помочь.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top