Exit — Процедура Delphi


Содержание

Клуб программистов

Delphi programming

Подписаться на рассылку:

осуществляет выход из функции или процедуры

Описание:

Delphi процедура Exit немедленно завершает выполнение текущей функции или процедуры.

При выходе из функции, результат содержит последнее значение.

Пример кода:

begin
// Ask the user for their name
ShowMessage(‘Name = ‘+AskForName);
end;

// Ask the user for first and second names
function TForm1.AskForName: string;
var
firstName, secondName : string;
begin
Result := ‘Lazy person’;
repeat
if not InputQuery(‘Test program’, ‘First name :’, firstName)
then Exit;
if not InputQuery(‘Test program’, ‘Second name :’, secondName)
then Exit;
until (firstName <> ») or (secondName <> »);

Result := firstName + ‘ ‘ + secondName;
end;

Результат выполнения:

If the user cancels from the first or second name dialogs, the ShowMessage dialog gives:

Delphi.DBExpress. Хранимые процедуры

В посте про хранимые процедуры мы уже создавали на стороне сервера MySQL хранимую процедуру добавления записи, с обработкой ошибок. В данном посте – создадим такую процедуру снова, и затем, вызовем её из Delphi.

Как создать хранимую процедуру на стороне сервера MySQL?

Код хранимой процедуры с обработкой ошибок и транзакцией на стороне сервера (вводим через консоль MySQL.exe)

Как удалить хранимую процедуру?

или в нашем примере…

Как вызвать хранимую процедуру из Delphi?

Можно разными путями – отправляя прямой запрос из компонентов SQLConnection или SQLQuery или компонентов множеств Simpledataset и др.

Нужно только следить – возвращает Ваша процедура множество или нет? Если возвращает (например, запрос SELECT) – тогда из simpldataset и других компонентов множеств, и тогда для активации множеств мы используем инструкции Open или Active. Если не возвращает (например INSERT INTO), тогда можно из SQLConncetion или SQLQuery. Ниже я привожу пример через sqlconnection1… и тогда, например, инструкция Exec для SQLStoredProc;

DelphiComponent.ru — бесплатно видеоуроки по Delphi, статьи, исходники

Процедура break и оператор goto

Но в Delphi есть и более элегантные средства для прерывания любых цик­лов — достаточно в нужном месте тела цикла записать слова breakили goto.

Слегка изменим последний пример:

Мы избавились от флага, и теперь при наступлении нужного нам события (i> 5) выполняется процедура break, и цикл заканчивается.

Действие процедуры breakв цикле whileрассмотрите самостоятельно, а цикл forпрерывается ещё проще:

Пример из школьной жизни. Нам нужно определить, под каким номером записан Ваня Ургант в классном журнале. Как учит нас Президент Медведев, вся документация должна вестись в элек­тронном виде. Значит, классный журнал можно представить себе как массив, в котором записаны все ученики (числом 30 голов). Всё — начинаем перебирать массив:

Как только мы найдём в журнале нашего Ваню, дальше искать смысла нет — Ваня Ургант единственный и неповторимый! В пере­менной nпосле окончания цикла мы и найдём номер Вани в класс­ном журнале. И хотя фамилия Вани начинается на букву «у», скорее всего это будет номер 1, ведь Ваня даже на Первом первый!

Можно привести и другие примеры — уже из спортивной жизни. Один удачный удар — нокаут, и бой между Николаем Валуевым и Ваней Ургантом преждевременно заканчивается. Такая же досада случилась и у хоккеистов сборной России по хоккею в матче с фин­нами, когда эти горячие парни забили нам шайбу в дополнитель­ном периоде. Есть и более огорчительные для мужского достоин­ства примеры, но упоминать их было бы неспортивно!

Вместо breakвы можете использовать оператор goto, который передаёт управление какому-нибудь оператору за пределами цикла. Этот оператор должен быть обозначен меткой (иначе получится, как в сказке, пойди ту­да, не знаю куда!), которая должна быть объявлена в процедуре:

В данных примерах действие процедуры break и оператора goto одинако­во — они просто передают управление следующему за циклом оператору, который печатает число выполненных итераций. Однако легко видеть, что оператор goto гораздо более дальнобойный — он может передать управле­ние любому оператору процедуры, которому предшествует метка (меток в процедуре может быть сколько угодно). Обычно применение операторов goto в программе не приветствуется, поскольку они нарушают логику ра­боты программы, перескакивая в произвольное место кода. Из этого сле­дует, что ими не следует злоупотреблять, но в некоторых случаях они мо­гут и облегчить понимание кода, если проверки выхода из цикла очень сложны. Обычно это бывает при выходе из вложенных циклов.

И последнее: при выходе из цикла с помощью goto с программой ничего не случится, но никогда не запрыгивайте извне внутрь цикла!

Процедура exit

Процедура exitдействует более радикально — она досрочно завершает не только цикл, но и всю подпрограмму, в которой этот цикл находится.

Например, если при выполнении цикла whileсработала процедура exit,

то число 6 в окне списка напечатано не будет, поскольку мы сразу же «уле­тим» в запроцедурное пространство. Такие «полные улёты» бывают по­лезны при выходе из вложенных циклов.

В последних версиях Delphiпроцедура exitможет возвращать значение то­го же типа, что и функция пользователя.

Так действует оператор returnв языках C# и C++.

Если функция exitне возвращает никакого значения, то ни круглые скобки, ни аргумент указывать не нужно.

Например, «по старинке» мы можем написать вот такую функцию GetRandom, которая возвращает случайное целое число в диапазоне iLo..iHi\

Эту же функцию мы можем обновить, возвращая случайное значение как аргумент функции exit:

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

Процедура continue

Процедура continue прерывает только текущую итерацию, и тело цикла выполняется с начала.

Продолжим терзать Ваню. Пусть вместе с ним в классе учатся Цекало, Светлаков, Мартиросян и другие лоботрясы, которые портят успевае­мость. Подсчитаем число прилежных учеников в классе:

Как только мы наткнёмся на двоечника, сразу же переходим к следующему ученику, а троечников, хорошистов и отличников валим в одну кучу. Те­перь классный руководитель точно знает, сколько билетов ему заказывать для поездки в Италию. Плюс ещё один билет — для Вани.

Более серьёзные и полезные примеры с процедурой continueвы найдёте дальше в этой книге.

Выводы

Используйте оператор for, когда число итераций известно заранее, а опе­раторы whileи repeat- если не известно.

Если вы уверены, что цикл может быть выполнен хотя бы 1 раз, исполь­зуйте repeat, в противном случае while.

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

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

Exit from an “if” in Delphi

you can exit a while loop with break.

How to exit from an if .

Is there a kind of GOTO in Delphi ?

9 Answers 9

You can use exceptions.

Call an Abort in inner if or loop, and catch EAbort exception where u want to continue

Like Piskvor mentioned , use nested if statement:

I am not in favour of using Exit’s this way, but you asked for it.

Like @mrabat suggested in a comment to @Arioch ‘The answer, you could use the fact that a finally block is always executed, regardless of Exit’s and exceptions, to your advantage here:

This is commonly implemented like this:

In general use of break or GOTO is not considered an elegant programming style. I suggest you just invert your condition and say:

here the code to execute

After reading the different comments, I decided to post an answer to show how to use the GoTo instruction. BTW, I prefer other methods explained in other answers avoiding its usage :

Use local inline procedure instead GOTO sentence; GOTO sentence decrease visibility of you code.

You can use the following method to exit out of an ‘if’ block by using ‘break’. Following example assumes that there are two edit boxes on the form. repeat . until true; replaces the usual begin . end;

Edit: Clarification, the solution is just assuming the question is a brain teaser. This is not my recommended way to handle the situation and I will never use this in my code.

// if cond1 then if cond2 then if cond3 then —

Использование процедур и функций в Delphi

Скобки

Добавление скобок при вызове процедур и функций без параметров уже давно не является новинкой в Delphi, тем не менее, эта возможность мало известна. Эту возможность оценят по достоинству те программисты, которым приходится работать на двух языках (C++ и Delphi), так как им не нужно будет постоянно помнить о разнице в синтаксисе при вызове процедур и функций в разных языках. В Delphi оба варианта, приведенные ниже, считаются корректными.

Возможность перегрузки

Впервые концепция перегрузки процедур и функций была реализована в Delphi 4. Она позволяет иметь несколько различных процедур и функций с одинаковыми именами, но с разными списками параметров. Такие процедуры и функции должны быть описаны с применением директивы overload.

procedure Test (I: integer); overload;
procedure Test (S: string); overload;
procedure Test (D: double); overload;

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

Передача параметров

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

Передача параметров по значению

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

procedure Test(s: string);

При вызове указанной процедуры будет создана копия передаваемой ей в качестве параметра строки s, с которой и будет работать процедура Test. При этом все внесенные в строку изменения никак не отразятся на исходной переменной s.

Однако это не относится к объектам. Например, если в функцию передается переменная (а точнее экземпляр объекта) TStringList, то в данном случае произойдет передача по ссылке (даже если это не указано явно). Этот способ передачи является у большинства самым излюбленным, но в тоже время является и самым не практичным, т.к. для выполнения метода выделяется дополнительная память для создания точной копией передаваемой переменой. Для решения этой проблемы следует использовать один из способов описанных ниже.

Передача параметров по ссылке

Pascal позволяет также передавать параметры в функции или процедуры по ссылке — такие параметры называются параметрами-переменными. Передача параметра по ссылке означает, что функция или процедура сможет изменить полученные значения параметров. Для передачи параметров по ссылке используется ключевое слово var, помещаемое в список параметров вызываемой процедуры или функции.

procedure ChangeMe(var x: longint);
begin
x := 2; // Параметр х изменен вызванной процедурой
end;

Вместо создания копии переменной x, ключевое слово var требует передачи адреса самой переменной x, что позволяет процедуре непосредственно изменять ее значение.

Передача параметров констант

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

procedure Test(const s: string );

Передача открытых массивов

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

function AddEmUp(A: array of integer): integer;

В открытом массиве можно передавать переменные, константы или выражения из констант.

Для получения информации о фактически передаваемом массиве параметров в функции или процедуре могут использоваться функции High, Low и SizeOf.

Object Pascal также поддерживает тип array of const, который позволяет передавать в одном массиве данные различных типов. Синтаксис объявления функций или процедур, использующих такой массив для получения параметров, следующий:

procedure WhatHaveIGot( A: array of const );

Вызвать объявленную выше функцию можно, например, с помощью такого оператора:

procedure WhatHaveIGot( [‘Text’, 10, 5.5, @WhatHaveIGot, 3.14, true, ‘c’] );

При передаче функции или процедуре массива констант все передаваемые параметры компилятор неявно конвертирует в тип TVarRec. Тип данных TVarRec объявлен в модуле System следующим образом:

PVarRec = ^TVarRec;
TVarRec = record
case Byte of
vtInteger: (VInteger: Integer; VType: Byte);
vtBoolean: (VBoolean: Boolean);
vtChar: (VChar: Char);
vtExtended: (VExtended: PExtended);
vtString: (VString: PShortString);
vtPointer: (VPointer: Pointer);
vtPChar: (VPChar: PChar);
vtObject: (VObject: TObject);
vtClass: (VClass: TClass);
vtWideChar: (VWideChar: WideChar);
vtPWideChar: (VPWideChar: PWideChar);
vtAnsiString: (VAnsiString: Pointer);
vtCurrency: (VCurrency: PCurrency);
vtVariant: (VVariant: PVariant);
vtInterface: (VInterface: Pointer);
vtWideString: (VWideString: Pointer);
vtInt64: (VInt64: PInt64);
end;

Поле VType определяет тип содержащихся в данном экземпляре записи TVarRec данных и может принимать одно приведенных значений.

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

procedure WhatHaveIGot( A: array of const );
var
i: integer;
TypeStr: string;
begin
for i := Low(A) to High(A) do
begin
case A[i].VType of
vtInteger : TypeStr := ‘Integer’;
vtBoolean : TypeStr := ‘Boolean’;
vtChar : TypeStr := ‘Char’;
vtExtended : TypeStr := ‘Extended’;
vtString : TypeStr := ‘String’;
vtPointer : TypeStr := ‘Pointer’;
vtPChar : TypeStr := ‘PChar’;
vtObject : TypeStr := ‘Object’;
vt ;
vtW ;
vtPW ;
vtAnsiString : TypeStr := ‘AnsiString’;
vtCurrency : TypeStr := ‘Currency’;
vtVariant : TypeStr := ‘Variant’;
vtInterface : TypeStr := ‘Interface’;
vtW ;
vtInt64 : TypeStr := ‘Int64’;
end;
ShowMessage( Format( ‘Array item %d is a %s’, [i, TypeStr] ) );
end;
end;

Значения параметров по умолчанию


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

procedure HasDefVal( s: string; i: integer = 0 );

Подобное объявление означает, что процедура HasDefVal может быть вызвана двумя путями. В первом случае — как обычно, с указанием обоих параметров:

procedure HasDefVal( ‘Hello’, 26 );

Во втором случае можно задать только значение параметра s, а для параметра i использовать значение, установленное по умолчанию:

procedure HasDefVal( ‘Hello’ );

При использовании значении параметров по умолчанию следует помнить о нескольких приведенных ниже правилах:

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

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

function Add( I1, I2: integer ): integer;
begin
Result := I1 + I2;
end;

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

function Add( I1, I2: integer; I3: integer = 0 ): integer;
begin
Result := I1 + I2 + I3;
end;

Директива

Директива <$X->запрещает вызов функций как процедур (с игнорированием возвращаемого результата). По умолчанию этот режим включен (<$X+>). Так вот, запомните, использование переменной Result недопустимо при сброшенном флажке опции Extended Syntax, расположенном во вкладке Compiler диалогового окна Project Options, или при указании директивы компилятора <$X->.

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

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

Exit — Процедура Delphi

Stack overflow (процедура EXIT )( Delphi) Не знаю почему, все выполнялось отлично, и вдруг начало выдаватся Stack overflow прога автоматически выгружается.

Function S: boolean;
begin
Result:=main.showblock.Checked;
if Result then
MessageBox(main.handle, ‘База данных заблокирована!’,
PAnsiChar(Application.title), 48);
end;

procedure Tmain.addbClick(Sender: TObject);
begin
if S then Exit;
end;

проверил, в процедуре S проблем нету, проблема в процедуре EXIT (выход с процедуры). Как решить проблему? 9 лет

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Процедуры управления программой

Procedure Break;

Процедура осуществляет досрочный выход из циклов For, While или Repeat.

Процедура должна находиться внутри этих циклов, иначе транслятор сообщит об ошибке.

Procedure Continue;

Процедура досрочно начинает следующую итерацию циклов For, While или Repeat.

Процедура должна находиться внутри этих циклов, иначе транслятор сообщит об ошибке.

Procedure Exit;

Осуществляет немедленный выход из текущей подпрограммы. Если текущей подпрограммой является главная программа, она завершает работу.

Прерывание выполнения функции(процедуры)

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

Прерывание функции или процедуры Delphi

Так вот, сегодня я расскажу о том, как прервать выполнение функции в ходе работы программы. В общем виде это выглядит так:

Где это может пригодиться?

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

Exit — Процедура Delphi

С целью поддержки структурной обработки исключительных ситуаций (exception) в Delphi введены новые расширения языка Pascal. В данной статье будет дано описание того, что из себя представляет такая обработка, почему она полезна, будут приведены соответствующий синтаксис Object Pascal и примеры использования исключительных ситуаций в Delphi.

Структурная обработка исключительных ситуаций

Структурная обработка исключительных ситуаций — это система, позволяющая программисту при возникновении ошибки (исключительной ситуации) связаться с кодом программы, подготовленным для обработки такой ошибки. Это выполняется с помощью языковых конструкций, которые как бы «охраняют» фрагмент кода программы и определяют обработчики ошибок, которые будут вызываться, если что-то пойдет не так в «охраняемом» участке кода. В данном случае понятие исключительной ситуации относится к языку и не нужно его путать с системными исключительными ситуациями (hardware exceptions), такими как General Protection Fault. Эти исключительные ситуации обычно используют прерывания и особые состояния «железа» для обработки критичной системной ошибки; исключительные ситуации в Delphi же независимы от «железа», не используют прерываний и используются для обработки ошибочных состояний, с которыми подпрограмма не готова иметь дело. Системные исключительные ситуации, конечно, могут быть перехвачены и преобразованы в языковые исключительные ситуации, но это только одно из применений языковых исключительных ситуаций.

При традиционной обработке ошибок, ошибки, обнаруженные в процедуре обычно передаются наружу (в вызывавшую процедуру) в виде возвращаемого значения функции, параметров или глобальных переменных (флажков). Каждая вызывающая процедура должна проверять результат вызова на наличие ошибки и выполнять соответствующие действия. Часто, это просто выход еще выше, в более верхнюю вызывающую процедуру и т.д. : функция A вызывает B, B вызывает C, C обнаруживает ошибку и возвращает код ошибки в B, B проверяет возвращаемый код, видит, что возникла ошибка и возвращает код ошибки в A, A проверяет возвращаемый код и выдает сообщение об ошибке либо решает сделать что-нибудь еще, раз первая попытка не удалась.

Такая «пожарная бригада» для обработки ошибок трудоемка, требует написания большого количества кода в котором можно легко ошибиться и который трудно отлаживать.

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

Структурная обработка исключительной ситуации замещает ручную обработку ошибок автоматической, сгенерированной компилятором системой уведомления. В приведенном выше примере, процедура A установила бы «охрану» со связанным обработчиком ошибки на фрагмент кода, в котором вызывается B. B просто вызывает C. Когда C обнаруживает ошибку, то создает (raise) исключительную ситуацию. Специальный код, сгенерированный компилятором и встроенный в Run-Time Library (RTL) начинает поиск обработчика данной исключительной ситуации. При поиске «защищенного» участка кода используется информация, сохраненная в стеке. В процедурах C и B нет такого участка, а в A — есть. Если один из обработчиков ошибок, которые используются в A, подходит по типу для возникшей в C исключительной ситуации, то программа переходит на его выполнение. При этом, область стека, используемая в B и C, очищается; выполнение этих процедур прекращается.

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

Без проверки возвращаемого кода после каждого вызова подпрограммы, код программы должен быть более простым, а скомпилированный код — более быстрым. При наличии исключительных ситуаций подпрограмма B не должна содержать дополнительный код для проверки возвращаемого результата и передачи его в A. B ничего не должна делать для передачи исключительной ситуации, возникшей в C, в процедуру A — встроенная система обработки исключительных ситуаций делает всю работу.

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

Модель исключительных ситуаций в Delphi

Модель исключительных ситуаций в Object Pascal является невозобновляемой(non-resumable). При возникновении исключительной ситуации Вы уже не сможете вернуться в точку, где она возникла, для продолжения выполнения программы (это позволяет сделать возобновляемая(resumable) модель). Невозобновляемые исключительные ситуации разрушают стек, поскольку они сканируют его в поисках обработчика; в возобновляемой модели необходимо сохранять стек, состояние регистров процессора в точке возникновения ошибки и выполнять поиск обработчика и его выполнение в отдельном стеке. Возобновляемую систему обработки исключительных ситуаций гораздо труднее создать и применять, нежели невозобновляемую.

Синтаксис обработки исключительных ситуаций

Теперь, когда мы рассмотрели, что такое исключительные ситуации, давайте дадим ясную картину, как они применяются. Новое ключевое слово, добавленное в язык Object Pascal — try. Оно используется для обозначения первой части защищенного участка кода. Существует два типа защищенных участков:

  • try..except
  • try..finally

Первый тип используется для обработки исключительных ситуаций. Его синтаксис:

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

Примеры обработки исключительных ситуаций

Ниже приведены процедуры A,B и C, обсуждавшиеся ранее, воплощенные в новом синтаксисе Object Pascal:

При ErrorCondition = True программа выдаст:

Возможно вас удивила декларация типа ‘ESampleError = . Описание новой объектной модели дается в других уроках. Здесь же достаточно сказать, что исключительные ситуации (exceptions) являются классами, частью новой объектной модели.

Процедура C проверяет наличие ошибки (в нашем случае это значение глобальной переменной) и, если она есть (а это так), C вызывает(raise) исключительную ситуацию класса ESampleError.

Процедура A помещает часть кода в блок try..except. Первая часть этого блока содержит часть кода, аналогично конструкции begin..end. Эта часть кода завершается ключевым словом except, далее следует один или более обработчиков исключительных ситуаций on xxxx do yyyy, далее может быть включен необязательный блок else, вся конструкция заканчивается end;. В конструкции, назначающей определенную обработку для конкретной исключительной ситуации (on xxxx do yyyy), после резервного слова on указывается класс исключительной ситуации, а после do следует собственно код обработки данной ошибки. Если возникшая исключительная ситуация подходит по типу к указанному после on, то выполнение программы переходит сюда (на код после do). Исключительная ситуация подходит в том случае, если она того же класса, что указан в on, либо является его потомком. Например, в случае on EFileNotFound обрабатываться будет ситуация, когда файл не найден. А в случае on EFileIO — все ошибки при работе с файлами, в том числе и предыдущая ситуация. В блоке else обрабатываются все ошибки, не обработанные до этого.

Приведенные в примере процедуры содержат код (строка с writeln), который отображает путь выполнения программы. Когда C вызывает exception, программа сразу переходит на обработчик ошибок в процедуре A, игнорируя оставшуюся часть кода в процедурах B и C.

После того, как найден подходящий обработчик ошибки, поиск оканчивается. После выполнения кода обработчика, программа продолжает выполняться с оператора, стоящего после слова end блока try..except (в примере — writeln(‘Exit A’)).

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

Рассмотрим модифицированную процедуру B:

Если C вызывает исключительную ситуацию, то программа уже не возвращается в процедуру B. А что же с теми 1000 байтами памяти, захваченными в B? Строка FreeMem(P,1000) не выполнится и Вы потеряете кусок памяти. Как это исправить? Нужно ненавязчиво включить процедуру B в процесс, например:

Если в A поместить вызов NewB вместо B, то программа выведет сообщения следующим образом:

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

Почему вызов GetMem не помещен внутрь блока try? Этот вызов может окончиться неудачно и вызвать exception EOutOfMemory. Если это произошло, то FreeMem попытается освободить память, которая не была распределена. Когда мы размещаем GetMem вне защищаемого участка, то предполагаем, что B сможет получить нужное количество памяти, а если нет, то более верхняя процедура получит уведомление EOutOfMemory.

А что, если требуется в B распределить 4 области памяти по схеме все-или-ничего? Если первые две попытки удались, а третья провалилась, то как освободить захваченную область память? Можно так:

Установив сперва указатели в NIL, далее можно определить, успешно ли прошел вызов GetMem.

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

Вызов исключительной ситуации

В процедуре C из примера мы уже могли видеть, как должна поступать программа при обнаружении состояния ошибки — она вызывает исключительную ситуацию:

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

Почти все существующие классы исключительных ситуаций являются наследниками базового класса Exception и не содержат новых свойств или методов. Класс Exception имеет несколько конструкторов, какой из них конкретно использовать — зависит от задачи. Описание класса Exception можно найти в on-line Help.

Доступ к экземпляру объекта exception

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

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

Рассмотрим модифицированную процедуру A в нашем примере:

Здесь все изменения внесены в строку

Пример демонстрирует еще одно новшество в языке Object Pascal — создание локальной переменной. В нашем примере локальной переменной является ESE — это тот самый экземпляр класса ESampleError, который был создан в процедуре C в момент вызова исключительного состояния. Переменная ESE доступна только внутри блока do. Свойство Message объекта ESE содержит сообщение, которое было передано в конструктор Create в процедуре C.

Есть еще один способ доступа к экземпляру exception — использовать функцию ExceptionObject:

Предопределенные обработчики исключительных ситуаций

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

  • Exception — базовый класс-предок всех обработчиков исключительных ситуаций.
  • EAbort — «скрытое» исключение. Используйте его тогда, когда хотите прервать тот или иной процесс с условием, что пользователь программы не должен видеть сообщения об ошибке. Для повышения удобства использования в модуле SysUtils предусмотрена процедура Abort, определенная, как:
  • EComponentError — вызывается в двух ситуациях:
    1. при попытке регистрации компоненты за пределами процедуры Register;
    2. когда имя компоненты не уникально или не допустимо.
  • EConvertError — происходит в случае возникновения ошибки при выполнении функций StrToInt и StrToFloat, когда конвертация строки в соответствующий числовой тип невозможна.
  • EInOutError — происходит при ошибках ввода/вывода при включенной директиве <$I+>.
  • EIntError — предок исключений, случающихся при выполнении целочисленных операций.
    • EDivByZero — вызывается в случае деления на ноль, как результат RunTime Error 200.
    • EIntOverflow — вызывается при попытке выполнения операций, приводящих к переполнению целых переменных, как результат RunTime Error 215 при включенной директиве <$Q+>.
    • ERangeError — вызывается при попытке обращения к элементам массива по индексу, выходящему за пределы массива, как результат RunTime Error 201 при включенной директиве <$R+>.
  • EInval — General Protection Fault. Соответствует RunTime Error 216.
  • EInval >Delphi, обладая прекрасными средствами доступа к данным, основывающимися на интерфейсе >Особенно важны два свойства класса EDBEngineError : Errors — список всех ошибок, находящихся в стеке ошибок BDE. Индекс первой ошибки 0;
    ErrorCount — количество ошибок в стеке.
    Объекты, содержащиеся в Errors, имеют тип TDBError. Доступные свойства класса TDBError:
    ErrorCode — код ошибки, возвращаемый Borland Database Engine;
    Category — категория ошибки, описанной в ErrorCode;
    SubCode — ‘субкод’ ошибки из ErrorCode;
    NativeError — ошибка, возвращаемая сервером БД. Если NativeError 0, то ошибка в ErrorCode не от сервера;
    Message — сообщение, переданное сервером, если NativeError не равно 0; сообщение BDE — в противном случае.
  • EDBEditError — наследник Exception ; вызывается, когда данные не совместимы с маской ввода, наложенной на поле. Объявлено в модуле Mask.
  • Заключение

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

    Илон Маск рекомендует:  Что такое код msql_dbname
    Понравилась статья? Поделиться с друзьями:
    Кодинг, CSS и SQL