Finally — Ключевое слово Delphi


Содержание

Блок try. finally

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

Смысл этой конструкции можно описать одним предложением: операторы, стоящие после finally , выполняются всегда.

Следующие за try операторы исполняются в обычном порядке. Если за это время не возникло никаких ИС, далее следуют те операторы, которые стоят после finally . В случае, если между try и finally произошла ИС, управление немедленно передается на операторы после finally , которые называются кодом очистки. Допустим, вы поместили после try операторы, которые должны выделить вам ресурсы системы (дескрипторы блоков памяти, файлов, контекстов устройств и т. п.). Тогда операторы, освобождающие их, следует поместить после finally , и ресурсы будут освобождены в любом случае. Блок try. finally , как можно догадаться, еще называется блоком защиты ресурсов.

Важно обратить внимание на такой факт: данная конструкция ничего не делает с самим объектом — исключительной ситуацией. Задача try. finally — только прореагировать на факт нештатного поведения программы и проделать определенные действия. Сама же ИС продолжает «путешествие» и вопрос ее обработки остается на повестке дня.

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

Можно также вкладывать обработчики друг в друга, предусмотрев в каждом специфическую реакцию на ту или иную ошибку:

On EDivByZero do

ShowMessage(‘Вариант 1: j=0’);

On EDivByZero do

ShowMessage(‘Вариант 2: i=0’);

Но все же идеально правильный случай — это сочетание блоков двух типов. В один из них помещается общее (освобождение ресурсов в finally ), в другой — особенное (конкретная реакция внутри except ).

НОВОСТИ ФОРУМА
Рыцари теории эфира
01.10.2020 — 05:20: ВОСПИТАНИЕ, ПРОСВЕЩЕНИЕ, ОБРАЗОВАНИЕ — Upbringing, Inlightening, Education ->
[center][Youtube]69vJGqDENq4[/Youtube][/center]
[center]14:36[/center]
Osievskii Global News
29 сент. Отправлено 05:20, 01.10.2020 г.’ target=_top>Просвещение от Вячеслава Осиевского — Карим_Хайдаров.
30.09.2020 — 12:51: ВОСПИТАНИЕ, ПРОСВЕЩЕНИЕ, ОБРАЗОВАНИЕ — Upbringing, Inlightening, Education ->
[center][Ok]376309070[/Ok][/center]
[center]11:03[/center] Отправлено 12:51, 30.09.2020 г.’ target=_top>Просвещение от Дэйвида Дюка — Карим_Хайдаров.
30.09.2020 — 11:53: ВОСПИТАНИЕ, ПРОСВЕЩЕНИЕ, ОБРАЗОВАНИЕ — Upbringing, Inlightening, Education ->
[center][Youtube]VVQv1EzDTtY[/Youtube][/center]
[center]10:43[/center]

интервью Раввина Борода https://cursorinfo.co.il/all-news/rav.
мой телеграмм https://t.me/peshekhonovandrei
мой твиттер https://twitter.com/Andrey54708595
мой инстаграм https://www.instagram.com/andreipeshekhonow/

[b]Мой комментарий:
Андрей спрашивает: Краснодарская синагога — это что, военный объект?
— Да, военный, потому что имеет разрешение от Росатома на манипуляции с радиоактивными веществами, а также иными веществами, опасными в отношении массового поражения. Именно это было выявлено группой краснодарцев во главе с Мариной Мелиховой.

[center][Youtube]CLegyQkMkyw[/Youtube][/center]
[center]10:22 [/center]

Доминико Риккарди: Россию ждёт страшное будущее (хотелки ЦРУ):
https://tainy.net/22686-predskazaniya-dominika-rikardi-o-budushhem-rossii-sdelannye-v-2000-godu.html

Завещание Алена Даллеса / Разработка ЦРУ (запрещено к ознакомлению Роскомнадзором = Жид-над-рус-надзором)
http://av-inf.blogspot.com/2013/12/dalles.html

[center][b]Сон разума народа России [/center]

[center][Youtube]CLegyQkMkyw[/Youtube][/center]
[center]10:22 [/center]

Доминико Риккарди: Россию ждёт страшное будущее (хотелки ЦРУ):
https://tainy.net/22686-predskazaniya-dominika-rikardi-o-budushhem-rossii-sdelannye-v-2000-godu.html

Завещание Алена Даллеса / Разработка ЦРУ (запрещено к ознакомлению Роскомнадзором = Жид-над-рус-надзором)
http://av-inf.blogspot.com/2013/12/dalles.html

[center][b]Сон разума народа России [/center]

Примеры исключений с Try . Finally .

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

ПРИМЕР 1: Написать программу для вычисления результата от деления одного числа на другое. Числа вводятся с клавиатуры. При выполнении деления использовать конструкцию try … finally

Примечание : В программе использованы вложенные инструкции Try:

Примечание : Числу не было присвоено значение — использование значения по умолчанию. Затем, программа заканчивается с сообщением об ошибке EDivByZero -, предложение finally не выловило ошибку.

Программирование на языке Delphi

Глава 4. Исключительные ситуации и надежное программирование


Авторы: А.Н. Вальвачев
К.А. Сурков
Д.А. Сурков
Ю.М. Четырько

Опубликовано: 26.11.2005
Исправлено: 10.12.2020
Версия текста: 1.0

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

4.1. Ошибки и исключительные ситуации

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

Хорошая программа должна справляться со своими ошибками и работать дальше, не зацикливаясь и не зависая ни при каких обстоятельствах. Для обработки ошибок можно, конечно, пытаться использовать структуры вида if then Exit. Однако в этом случае ваш стройный и красивый алгоритм решения основной задачи обрастет уродливыми проверками так, что через неделю вы сами в нем не разберетесь. Из этой почти тупиковой ситуации среда Delphi предлагает простой и элегантный выход — механизм обработки исключительных ситуаций.

Исключительная ситуация (exception) — это прерывание нормального хода работы программы из-за невозможности правильно выполнить последующие действия.

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

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

Механизм обработки исключительных ситуаций довольно сложен в своей реализации, но для программиста он прост и прозрачен. Для его использования в язык Delphi введены специальные конструкции try . except . end , try . finally . end и оператор raise , рассмотренные в этой главе.

4.2. Классы исключительных ситуаций

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

Классы исключительных ситуаций образуют иерархию, корнем которой является класс Exception . Класс Exception описывает самый общий тип исключительных ситуаций, а его наследники — конкретные виды таких ситуаций (таблица 4.1). Например, класс EOutOfMemory порожден от Exception и описывает ситуацию, когда свободная оперативная память исчерпана.

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

Класс исключительных ситуаций Описание
EAbort «Безмолвная» исключительная ситуация, используемая для выхода из нескольких уровней вложенных блоков или подпрограмм. При этом на экран не выдается никаких сообщений об ошибке. Для генерации исключительной ситуации класса EAbort нужно вызвать стандартную процедуру Abort.
EInOutError Ошибка доступа к файлу или устройству ввода-вывода. Код ошибки содержится в поле ErrorCode.
EExternal Исключительная ситуация, возникшая вне программы, например, в операционной системе.
EExternalException Исключительная ситуация, возникшая за пределами программы, например в DLL-библиотеке, разработанной на языке C++.
EHeapException Общий класс исключительных ситуаций, возникающих при работе с динамической памятью. Является базовым для классов EOutOfMemory и EInvalidPointer.Внимание! Создание исключительных ситуаций этого класса (и всех его потомков) полностью берет на себя среда Delphi, поэтому никогда не создавайте такие исключительные ситуации с помощью оператора raise .
EOutOfMemory Свободная оперативная память исчерпана (см. EHeadException).
EInvalidPointer Попытка освободить недействительный указатель (см. EHeadException). Обычно это означает, что указатель уже освобожден.
EIntError Общий класс исключительных ситуаций целочисленной арифметики, от которого порождены классы EDivByZero, ERangeError и EIntOverflow.
EDivByZero Попытка деления целого числа на нуль.
ERangeError Выход за границы диапазона целого числа или результата целочисленного выражения.
EIntOverflow Переполнение в результате целочисленной операции.
EMathError Общий класс исключительных ситуаций вещественной математики, от которого порождены классы EInvalidOp, EZeroDivide, EOverflow и EUnderflow.
EInvalidOp Неверный код операции вещественной математики.
EZeroDivide Попытка деления вещественного числа на нуль.
EOverflow Потеря старших разрядов вещественного числа в результате переполнения разрядной сетки.
EUnderflow Потеря младших разрядов вещественного числа в результате переполнения разрядной сетки.
EInvalidCast Неудачная попытка приведения объекта к другому классу с помощью оператора as .
EConvertError Ошибка преобразования данных с помощью функций IntToStr, StrToInt, StrToFloat, StrToDateTime.
EVariantError Невозможность преобразования варьируемой переменной из одного формата в другой.
EAccessViolation Приложение осуществило доступ к неверному адресу в памяти. Обычно это означает, что программа обратилась за данными по неинициализированному указателю.
EPrivilege Попытка выполнить привилегированную инструкцию процессора, на которую программа не имеет права.
EStackOverflow Стек приложения не может быть больше увеличен.
EControlC Во время работы консольного приложения пользователь нажал комбинацию клавиш Ctrl+C.
EAssertionFailed Возникает при вызове процедуры Assert, когда первый параметр равен значению False.
EPackageError Проблема во время загрузки и инициализации библиотеки компонентов.
EOSError Исключительная ситуация, возникшая в операционной системе.
Таблица 4.1. Классы исключительных ситуаций

Наследование классов позволяет создавать семейства родственных исключительных ситуаций. Примером такого семейства являются классы исключительных ситуаций вещественной математики, которые объявлены в модуле SysUtils следующим образом.

Класс исключительных ситуаций EMathError является базовым для классов EInvalidOp, EZeroDivide, EOverflow и EUnderflow, поэтому, обрабатывая исключительные ситуации класса EMathError, вы будете обрабатывать все ошибки вещественной математики, включая EInvalidOp, EZeroDivide, EOverflow и EUnderflow.

Нетрудно заметить, что имена классов исключений начинаются с буквы E (от слова Exception). Этого правила полезно придерживаться при объявлении собственных классов исключений, например:

Как описываются классы исключительных ситуаций понятно, рассмотрим теперь, как такие ситуации обрабатываются.

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


4.3.1. Создание исключительной ситуации

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

Данный оператор создает объект класса EOutOfMemory (класс ошибок исчерпания памяти) и прерывает нормальное выполнение программы. Вызывающие подпрограммы могут эту исключительную ситуацию перехватить и обработать. Для этого в них организуется так называемый защищенный блок :

Между словами try и except помещаются защищаемые от ошибок операторы. Если при выполнении любого из этих операторов возникает исключительная ситуация, то управление передается операторам между словами except и end , образующим блок обработки исключительных ситуаций. При нормальном (безошибочном) выполнении программы блок except . end пропускается (рисунок 4.1).

Рисунок 4.1. Логика работы оператора try…except…end

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

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

4.3.2. Распознавание класса исключительной ситуации

Распознавание класса исключительной ситуации выполняется с помощью конструкций

которые записываются в секции обработки исключительной ситуации, например:

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

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

На самом высоком уровне программы бывает необходимо перехватывать все исключительные ситуации, чтобы в случае какой-нибудь неучтенной ошибки корректно завершить приложение. Для этого применяется так называемый обработчик по умолчанию (default exception handler). Он записывается в секции except после всех операторов on и начинается ключевым словом else :

Учтите, что отсутствие части else соответствует записи else raise , которое нет смысла использовать явно. Мы со своей стороны вообще не советуем вам пользоваться обработкой исключительных ситуаций по умолчанию, поскольку все ваши приложения будут строиться, как правило, на основе библиотеки VCL, в которой обработка по умолчанию уже предусмотрена.

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

В качестве примера обработки исключительной ситуации рассмотрим две функции: StringToCardinal и StringToCardinalDef.

Функция StringToCardinal выполняет преобразование строки в число с типом Cardinal. Если преобразование невозможно, функция создает исключительную ситуацию класса EConvertError.

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

Для преобразования исходной строки в число используется определенная выше функция StringToCardinal. Если при преобразовании возникает исключительная ситуация, то она «поглощается» функцией StringToCardinalDef, которая в этом случае возвращает значение параметра Default. Если происходит какая-нибудь другая ошибка (не EConvertError), то управление передается внешнему блоку обработки исключительных ситуаций, из которого была вызвана функция StringToCardinalDef.

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

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

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

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

4.3.5. Доступ к объекту, описывающему исключительную ситуацию

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

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

Переменная E — это объект исключительной ситуации, ShowMessage — процедура модуля DIALOGS, отображающая на экране небольшое окно с текстом и кнопкой OK. Свойство Message типа string определено в классе Exception , оно содержит текстовое описание ошибки. Исходное значение для текста сообщения указывается при конструировании объекта исключительной ситуации.

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

4.4. Защита выделенных ресурсов от пропадания


4.4.1. Утечка ресурсов и защита от нее

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

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

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

Рисунок 4.2. Логика работы оператора try…except…end

Блок try . finally . end обладает еще одной важной особенностью. Если он помещен в цикл, то вызов из защищенного блока процедуры Break с целью преждевременного выхода из цикла или процедуры Continue с целью перехода на следующую итерацию цикла сначала обеспечивает выполнение секции finally . end , а затем уже выполняется соответствующий переход. Это утверждение справедливо также и для процедуры Exit (выход из подпрограммы).

Как показывает практика, подпрограммы часто распределяют сразу несколько ресурсов и используют их вместе. В таких случаях применяются вложенные блоки try . finally . end :

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

4.5. Итоги

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

Finally — Ключевое слово 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.
  • Заключение

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

    Правильная обработка освобождения ресурсов через try…finally в Delphi

    Есть много разных вариантов как можно использовать конструкцию try. finally для освобождения ресурсов. Многие из них работают неверно в особых ситуациях. Рассмотрим несколько вариантов подробнее.

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

    Прежде всего, установим ReportMemoryLeaksOnShutdown := True в dpr файле, для того чтобы отслеживать утечки памяти.

    Finally — Ключевое слово Delphi

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

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

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

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

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

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

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

    Исключения, возникающие при работе с базами данных

      1. Обзор
      2. С целью поддержки структурной обработки исключительных ситуаций ( exception ) в Delphi введены новые расширения языка Pascal. В данной статье будет дано описание того, что из себя представляет такая обработка, почему она полезна, будут приведены соответствующий синтаксис Object Pascal и примеры использования исключительных ситуаций в D elphi.
      3. Структурная обработка исключительных ситуаций
      4. Структурная обработка исключительных ситуаций — это система, позволяющая программисту при возникновении ошибки (исключительной ситуации) связаться с кодом программы, подготовленным для обработки такой ошибки. Это выполняется с помощью языковых конструкций, которые как бы “охраняют” фрагмент кода программы и определяют обработчики ошибок, которые будут вызываться, если что-то пойдет не так в “охраняемом” участке кода. В данном случае понятие исключительной ситуации относится к языку и не нужно его путать с системными исключительными ситуациями (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 — встроенная система обработки исключительных ситуаций делает всю работу.

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

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

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

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

    on Exception1 do Statement;

    on Exception2 do Statement;

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

        1. Примеры обработки исключительных ситуаций
        2. Ниже приведены процедуры A,B и C, обсуждавшиеся ранее, воплощенные в новом синтаксисе Object Pascal:

        if (ErrorCondition) then

        writeln(‘Raising exception in C’);

        writeln(‘Enter A»s try block’);

        writeln(‘After B call’);

        on ESampleError do

        writeln(‘Inside A»s ESampleError handler’);


        on ESomethingElse do

        writeln(‘Inside A»s ESomethingElse handler’);

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

        Enter A’s try block

        Raising exception in C

        Inside A’s ESampleError handler

        Возможно вас удивила декларация типа ‘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 в процесс, например:

        writeln(‘enter NewB»s try block’);

        writeln(‘end of NewB»s try block’);

        writeln(‘inside NewB»s finally block’);

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

        Enter A’s try block

        enter NewB’s try block

        Raising exception in C

        inside NewB’s finally block

        Inside A’s ESampleError handler

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

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

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

        writeln(‘enter B»s try block’);

        writeln(‘end of B»s try block’);

        writeln(‘inside B»s finally block’);

        if P <> nil then FreeMem(P, 1000);

        if Q <> nil then FreeMem(Q, 1000);

        if R <> nil then FreeMem(R, 1000);

        if S <> nil then FreeMem(S, 1000);

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

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

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

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

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

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

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

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

        writeln(‘Enter A»s try block’);

        writeln(‘After B call’);

        on E: ESampleError do writeln(E.Message);

        on ESomethingElse do

        writeln(‘Inside A»s ESomethingElse handler’);

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

        on ESE: ESampleError do writeln(ESE.Message);

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

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

        on ESampleError do

        writeln( ESample Error(ExceptionObject).Message);

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

        • Exception — базовый класс-предок всех обработчиков исключительных ситуаций.
        • EAbort — “ скрытое” исключение. Используйте его тогда, когда хотите прервать тот или иной процесс с условием, что пользователь программы не должен видеть сообщения об ошибке. Для повышения удобства использования в модуле SysUtils предусмотрена процедура Abort , определенная, как:

        raise EAbort.CreateRes(SOperationAborted) at ReturnAddr;

        • EComponentError — вызывается в двух ситуациях:
      5. 1) при попытке регистрации компоненты за пределами процедуры Register;

        2) когда имя компоненты не уникально или не допустимо.

        • EConvertError — происходит в случае возникновения ошибки при выполнении функций StrToInt и StrToFloat , когда конвертация строки в соответствующий числовой тип невозможна.
        • EInOutError — происходит при ошибках ввода/вывода при включенной директиве <$I+>.
        • EIntError — предок исключений, случающихся при выполнении целочисленных операций.
        • EDivByZero — вызывается в случае деления на ноль, как результат RunTime Error 200.
        • EIntOverflow — вызывается при попытке выполнения операций, приводящих к переполнению целых переменных, как результат RunTime Error 215 при включенной директиве <$Q+>.
        • ERangeError — вызывается при попытке обращения к элементам массива по индексу, выходящему за пределы массива, как результат RunTime Error 201 при включенной директиве <$R+>.
        • EInvalidCast — происходит при попытке приведения переменных одного класса к другому классу, несовместимому с первым (например, приведение переменной типа TListBox к TMemo).
        • EInvalidGraphic — вызывается при попытке передачи в LoadFromFile файла, несовместимого графического формата.
        • EInvalidGraphicOperation — вызывается при попытке выполнения операций, неприменимых для данного графического формата (например, Resize для TIcon).
        • EInvalidObject — реально нигде не используется, объявлен в Controls.pas.
        • EInvalidOperation — вызывается при попытке отображения или обращения по Windows-обработчику (handle) контрольного элемента, не имеющего владельца (например, сразу после вызова MyControl:=TListBox.Create(. ) происходит обращение к методу Refre sh).
        • EInvalidPointer — происходит при попытке освобождения уже освобожденного или еще неинициализированного указателя, при вызове Dispose(), FreeMem() или деструктора класса.
        • EListError — вызывается при обращении к элементу наследника TList по индексу, выходящему за пределы допустимых значений (например, объект TStringList содержит только 10 строк, а происходит обращение к одиннадцатому).
        • EMathError — предок исключений, случающихся при выполнении операций с плавающей точкой.
        • EInvalidOp — происходит, когда математическому сопроцессору передается ошибочная инструкция. Такое исключение не будет до конца обработано, пока Вы контролируете сопроцессор напрямую из ассемблерного кода.
        • EOverflow — происходит как результат переполнения операций с плавающей точкой при слишком больших величинах. Соответствует RunTime Error 205.
        • Underflow — происходит как результат переполнения операций с плавающей точкой при слишком малых величинах. Соответствует RunTime Error 206.
        • EZeroDivide — вызывается в результате деления на ноль.
        • EMenuError — вызывается в случае любых ошибок при работе с пунктами меню для компонент TMenu, TMenuItem, TPopupMenu и их наследников.
        • EOutlineError — вызывается в случае любых ошибок при работе с TOutLine и любыми его наследниками.
        • EOutOfMemory — происходит в случае вызовов New(), GetMem() или конструкторов классов при невозможности распределения памяти. Соответствует RunTime Error 203.
        • EOutOfResources — происходит в том случае, когда невозможно выполнение запроса на выделение или заполнение тех или иных Windows ресурсов (например таких, как обработчики — handles).
        • EParserError — вызывается когда Delphi не может произвести разбор и перевод текста описания формы в двоичный вид (часто происходит в случае исправления текста описания формы вручную в IDE Delphi).
        • EPrinter — вызывается в случае любых ошибок при работе с принтером.
        • EProcessorException — предок исключений, вызываемых в случае прерывания процессора- hardware breakpoint. Никогда не включается в DLL, может обрабатываться только в “цельном” приложении.
        • EBreakpoint — вызывается в случае останова на точке прерывания при отладке в IDE Delphi. Среда Delphi обрабатывает это исключение самостоятельно.
        • EFault — предок исключений, вызываемых в случае невозможности обработки процессором тех или иных операций.
          • EGPFault — вызывается, когда происходит “общее нарушение защиты” — General Protection Fault. Соответствует RunTime Error 216.
          • EInvalidOpCode — вызывается, когда процессор пытается выполнить недопустимые инструкции.
          • EPageFault — обычно происходит как результат ошибки менеджера памяти Windows, вследствие некоторых ошибок в коде Вашего приложения. После такого исключения рекомендуется перезапустить Windows.
          • EStackFault — происходит при ошибках работы со стеком, часто вследствие некорректных попыток доступа к стеку из фрагментов кода на ассемблере. Компиляция Ваших программ со включенной проверкой работы со стеком <$S+>помогает отследить такого рода ошибки.
        • ESingleStep — аналогично EBreakpoint, это исключение происходит при пошаговом выполнении приложения в IDE Delphi, которая сама его и обрабатывает.
        • EPropertyError — вызывается в случае ошибок в редакторах свойств, встраиваемых в IDE Delphi. Имеет большое значение для написания надежных property editors. Определен в модуле DsgnIntf.pas.
        • EResNotFound — происходит в случае тех или иных проблем, имеющих место при попытке загрузки ресурсов форм — файлов .DFM в режиме дизайнера. Часто причиной таких исключений бывает нарушение соответствия между определением класса формы и ее описанием на уровне ресурса (например,вследствие изменения порядка следования полей-ссылок на компоненты, вставленные в форму в режиме дизайнера).
        • EStreamError — предок исключений, вызываемых при работе с потоками.
        • EFCreateError — происходит в случае ошибок создания потока (например, при некорректном задании файла потока).
        • EFilerError — вызывается при попытке вторичной регистрации уже зарегистрированного класса (компоненты). Является, также, предком специализированных обработчиков исключений, возникающих при работе с классами компонент.
          • EClassNotFound — обычно происходит, когда в описании класса формы удалено поле-ссылка на компоненту, вставленную в форму в режиме дизайнера. Вызывается, в отличие от EResNotFound, в RunTime.
          • EInvalidImage — вызывается при попытке чтения файла, не являющегося ресурсом, или разрушенного файла ресурса, специализированными функциями чтения ресурсов (например, функцией ReadComponent).


          • EMethodNotFound — аналогично EClassNotFound, только при несоответствии методов, связанных с теми или иными обработчиками событий.
          • EReadError — происходит в том случае, когда невозможно прочитать значение свойства или другого набора байт из потока (в том числе ресурса).
          • EFOpenError — вызывается когда тот или иной специфированный поток не может быть открыт (например, когда поток не существует).
        • EStringListError — происходит при ошибках работы с объектом TStringList (кроме ошибок, обрабатываемых TListError).

        Delphi, обладая прекрасными средствами доступа к данным, основывающимися на интерфейсе IDAPI, реализованной в виде библиотеки Borland Database Engine (BDE), включает ряд обработчиков исключительных ситуаций для регистрации ошибок в компонентах VCL работающим с БД. Дадим краткую характеристику основным из них:

        • EDatabaseError — наследник Exception ; происходит при ошибках доступа к данным в компонентах-наследниках TDataSet. Объявлено в модуле DB . Ниже приведен пример из Delphi On-line Help, посвященный этому исключению:

        Обработка исключительных ситуаций в Delphi.

        Цель работы: изучение основных способов обработки исключительных ситуаций в Delphi, приобретение практических навыков при использовании основных блоков защиты кода try…except… и try…finally…

        Краткие теоретические сведения.

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

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

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

        Таблица 1.ИС целочисленной математики (порождены отEIntError)

        Тип Условие возникновения
        EDivByZero Попытка деления на ноль (целое число)
        ERangeError Число или выражение выходит за допустимый диапазон
        EIntOverflow Целочисленное переполнение

        Таблица 2.ИС математики с плавающей точкой (порождены от EMathError)

        Тип Условие возникновения
        EInvalidOp Неверная операция
        EZeroDivide Попытка деления на ноль
        EOverflow Переполнение с плавающей точкой
        EUnderflow Исчезновение порядка
        EInvalidArgument Неверный аргумент математических функций

        Защитные конструкции языка Object Pascal

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

        Блок try..except

        Для реакции на конкретный тип ситуации применяется блок try..except. Синтаксис его следующий:

        on EExceptionl do ;

        on EException2 do ;

        else //обработчик прочих ИС

        Выполнение блока начинается с секции try. При отсутствии исключительных ситуаций только она и выполняется. Секция except получает управление в случае возникновения ИС. После обработки происходит выход из защищенного блока, и управление обратно в секцию try не передается; выполняются операторы, стоящие после end.

        Если вы хотите обработать любую ИС одинаково, независимо от ее класса, вы можете писать код прямо между операторами except и end. Но если обработка отличается, здесь можно применять набор директив on. do, определяющих реакцию приложения на определенную ситуацию. Каждая директива связывает ситуацию (on. ), заданную своим именем класса, с группой операторов (do. ).

        Иногда замена if. then на try. except не приводит к экономии кода. Однако если при решении вычислительной задачи проверять на возможное появление ИС приходится не один, а множество раз, то выигрыш неоспорим — достаточно одного блока try. except на все вычисления.

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

        Если возникла ситуация, не определенная ни в одной из директив, выполняются те операторы, которые стоят после else. Если и их нет, то ИС считается не обработанной и будет передана на следующий уровень обработки. Этим следующим уровнем может быть другой оператор try. except, который содержит в себе данный блок.

        Блок try. finally

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

        Следующие за try операторы исполняются в обычном порядке. Если за это время не возникло никаких ИС, далее следуют те операторы, которые стоят после finally. В случае если между try и finally произошла ИС, управление немедленно передается операторам части finally…end. Таким образом, операторы, стоящие после finally, выполняются всегда. Блок try. finally еще называется блоком защиты ресурсов. Данная конструкция ничего не делает с самим объектом — исключительной ситуацией. Задача try. finally — только прореагировать на факт нештатного поведения программы и проделать определенные действия. Сама же ИС остается необработанной.

        Блоки защиты ресурсов и обработчики ИС, как и другие блоки, могут быть вложенными:

        Вызов исключения

        В некоторых случаях бывает необходимо инициировать собственное исключение. Для этого используется зарезервированное слово raise (возбудить). Если это слово встретилось в секции try.. .except или try.. .finally, немедленно начинают свою работу секции except. end и finally. end соответственно.

        Слово raise возбуждает исключение самого общего класса Exception. Если программист желает возбудить исключение конкретного типа (не важно — стандартного или собственного), он должен явно указать класс создаваемого в этот момент объекта путем вызова его конструктора. Например, следующий оператор возбудит ошибку ввода/вывода:

        Такой прем — единственная возможность возбудить нестандартное исключение.

        Вывод сообщений

        Для вывода окна с сообщением предусмотрено несколько функций.

        1. MessageDlg(const Msg: string; AType: TMsgDlgType;AButtons: TMsgDlgType;

        Отображает окно с сообщением Msg, с пиктограммой, задаваемой параметром AType, с набором кнопок, задаваемым параметром AButtons, и с темой справки, задаваемой параметром HelpCtx. Возвращает результат, указывающий, какую кнопку в диалоговом окне нажал пользователь.

        2. MessageDlgPos(const Msg: string; AType: TMsgDlgType; Buttons: TMsgDlgType;

        HelpCtx: Longint; X,Y: integer):Word;

        Отображает окно с сообщением Msg, с пиктограммой, задаваемой параметром AType, с набором кнопок, задаваемым параметром AButtons, и с темой справки, задаваемой параметром HelpCtx. Параметры X и Y задают экранные координаты верхнего левого угла окна. Возвращает результат, указывающий, какую кнопку в диалоговом окне нажал пользователь.

        3. ShowMessage(const Msg: string);

        Отображает окно с сообщением Msg, с кнопкой OK.

        Пример создания приложения с обработкой ИС.

        Задание. Создать Windows-приложение для отображения матрицы. Матрица должна загружаться из файла, выбранного с помощью компонента OpenDialog.

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

        1. Страница — компонент OpenDialog .

        2. Страница — компонент StringGrid .

        3. Страница — компонент Button .

        Один из возможных вариантов панели интерфейса создаваемого приложения показан на рис.1.

        При работе с массивами ввод и вывод информации на экран удобно организовывать с помощью компонента StringGrid. Компонент StringGrid используется для отображения информации в виде таблицы. Пиктограмма компонента StringGrid находится на странице Additional Палитры Компонентов. Таблица содержит две зоны – фиксированную и рабочую. Фиксированная зона служит для вывода наименований строк и столбцов рабочей зоны и управления их размерами с помощью “мыши”. Фиксированная зона выделена другим цветом и в нее запрещен ввод информации с клавиатуры.

        StringGrid
        OpenDialog

        Количество строк и столбцов фиксированной зоны устанавливается в свойствах FixedRows и FixedCols соответственно. Рабочая зона содержит RowCountстрок и ColCountстолбцов информации, которую можно изменять как программно, так и с помощью “мыши” или клавиатуры. Доступ к содержимому ячеек в программе осуществляется с помощью свойства Cells[ACol, ARow: integer]: string, где ACol-номер столбца, а ARow – номер строки таблицы, причем нумерация начинается с нуля. По умолчанию в компонент StringGrid запрещен ввод информации с клавиатуры, для разрешения ввода информации в ячейки необходимо в Инспекторе Объектов дважды щелкнуть “мышью” на символе + свойства +Options и в открывшемся списке опций установить значение goEditing в True.

        Так как в нашем задании фиксированная зона не используется, то в Инспекторе Объектов значения свойств FixedCols и FixedRowsможно установить равными 0. Организуем файл таким образом, чтобы в первой строке находилось количество строк матрицы, во второй – количество столбцов, а каждый элемент матрицы — в отдельной строке. Тогда, прочитав первые 2 цифры, можно установить значения свойств RowCount и ColCount компонента StringGrid. Так как при работе с файлами могут возникать ошибки ввода-вывода, то необходимо использовать защитные конструкции try..except и try..finally. В общем случае метод-обработчик события onClickдля компонента Button будет выглядеть следующим образом:

        procedure TForm1.LoadClick(Sender: TObject);

        if opendialog1.Execute then

        if FileExists(OpenDialog1.FileName) then

        reset(f1); // здесь возможна ошибка EInOutError

        readln(f1,c); // здесь возможна ошибка EInOutError

        readln(f1,r); // здесь возможна ошибка EInOutError

        for i:=0 to r-1 do

        for j:=0 to c-1 do

        readln(f1,k); // здесь возможна ошибка EInOutError

        on E:EInOutError do showmessage(‘Ошибка при работе с файлом: ‘+inttostr(E.Errorcode));

        on EConvertError do showmessage(‘Ошибка преобразования типов’);

        else showmessage(‘Файл не найден’);

        Содержание отчета.

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

        Контрольные вопросы.

        1. Обработка исключительных ситуаций в Delphi: блок try …except.

        2. Обработка исключительных ситуаций в Delphi: блок try .. finally.

        3. Обработка исключительных ситуаций в Delphi: вызов исключений (raise).

        4. Компоненты StringGrid, SpinEdit: назначение, основные свойства.

        Выполнить задание необходимо в соответствии с вариантом. Каждое задание предусматривает работу с одномерными массивами и матрицами. Исходные массивы должны вводиться из файла при нажатии на кнопку «Загрузить». Выбор файла реализовать с помощью компонента OpenDialog. На форме предусмотреть кнопку «Сохранить», при нажатии на которую результат сохраняется в файле. Программа должна обрабатывать все исключительные ситуации, которые могут возникнуть при вводе матрицы, формировании массивов и т. д. В случае возникновения ошибки должно выводиться окно с соответствующим сообщением. Номер строки или столбца массивов можно указывать в компоненте SpinEdit. Компонент SpinEdit находится на странице Samples Палитры Компонентов. Доступ к содержимому внутри окна компонента можно получить, используя свойство Text.

        1. Создать приложения для вычисления и отображения 2-х одномерных массивов B и С. Элементы массивов должны быть получены из исходной целочисленной матрицы А в результате вычисления формул: ln(a[р,j]) (для массива В) и 1/ln(a[р,j]) (для массива С). Организовать выбор номера строки р матрицы А. Массивы должны формироваться при нажатии на кнопку «Пуск».

        2. Заданы: целочисленная матрица А размером NxM и вектор В. Сформировать вектор С, элементы которого равны целой части частного от деления а[i,p]/cos(b[i]). Организовать выбор номера столбца p матрицы А. Вектор С должен формироваться при нажатии на кнопку «Пуск».

        3. Заданы: целочисленная матрица А размером NxM и вектор В. Сформировать вектор С, элементы которого равны целой части частного от деления а[р,j]/cos(b[j]). Организовать выбор номера строки р матрицы А. Вектор С должен формироваться при нажатии на кнопку «Пуск».

        4. Заданы: целочисленная матрица А размером NxM и вектор В. Сформировать вектор С, элементы которого равны целой части частного от деления b[i]/sin(а[i,р])). Организовать выбор номера столбца p матрицы А. Вектор С должен формироваться при нажатии на кнопку «Пуск».

        5. Задана целочисленная матрица А размером NxM. Сформировать вектор В, элементы которого равны tg(a[i,р]). Организовать выбор номера столбца p матрицы А. Вектор В должен формироваться при нажатии на кнопку «Пуск».

        6. Заданы вектора В и С размером N. Сформировать вектор А размером N, элементы которого равны целой части частного от деления с[i]/cos(b[i]). Вектор А должен формироваться при нажатии на кнопку «Пуск».

        7. Создать приложения для вычисления и отображения 2-х одномерных массивов B и С. Элементы массивов должны быть получены из исходной целочисленной матрицы А в результате вычисления формул: a[р,j]/ a[р-1,j] (для массива В) и a[р,j]/ a[р+1,j] (для массива С). Организовать выбор номера строки р матрицы А. В случае выбора в качестве р номера первой или последней строки организовать замену на номер последней или первой строки соответственно. Массивы должны формироваться при нажатии на кнопку «Пуск».

        8. Заданы: целочисленная матрица А размером NxM и вектор В. Сформировать вектор С, элементы которого равны целой части частного от деления а[р,j]/sin(b[j]). Организовать выбор номера строки р матрицы А. Вектор С должен формироваться при нажатии на кнопку «Пуск».

        9. Задана целочисленная матрица А размером NxM. Сформировать вектор В, элементы которого равны sin(a[i,р])/a[i,р]. Организовать выбор номера столбца p матрицы А. Вектор В должен формироваться при нажатии на кнопку «Пуск».

        10. Заданы: целочисленная матрица А размером NxM и вектор В. Сформировать вектор С, элементы которого равны целой части частного от деления а[i,p]/sin(b[i]). Организовать выбор номера столбца p матрицы А. Вектор С должен формироваться при нажатии на кнопку «Пуск».

        Новые книги

        Курс посвящен изучению языка программирования JavaScript.

        JavaScript является языком сценариев (скриптов), который применяют в основном для создания на Web-страницах интерактивных элементов. Его можно использовать для построения меню, проверки правильности заполнения форм, смены изображений или для чего-то еще, что можно сделать на Web-странице.

        Глава 2. Исключительные ситуации и интерфейсы в Delphi

        ГЛАВА 2

        • Понятие исключительной ситуации, ее обработка средствами Delphi
        • Обработка RTL-исключений.Иерархия исключений
        • Создание собственных исключений
        • Интерфейсы и их совместное использование классами
        • Интерфейс IUnknown
          • Класс TInterfasedObject
          • Использование оператора as
          • Использование ключевого слова implements
        • Использование инрефейсов в распределительных приложениях

        Большинство разработчиков на Delphi создают довольно сложные программы. Сложная программа подразумевает разносторонее взаимодействие с операционной системой и приложениями операционной системы. Любое из этих взаимодействий может завершиться неправильно. Примеров этого можно привести очень много, от банального деления на ноль, до открытия несуществующего файла. Обычно для обхода таких ситуаций разработчику приходится вводить многочисленные проверки. Но любой разработчик просто не в состоянии рассмотреть все ситуации, которые могут возникнуть у его программы при взаимодействии с операционной системой и другими приложениями. Именно для таких непредвиденных событий была придумана структурированная обработка исключительных ситуаций. Первоначально она была создана для разработчиков под Windows NT, впоследствии структурированная обработка получила поддержку и в операционных системах Windows 9x. Большинство современных программных сред для создания приложений под Windows поддерживают обработку исключительных ситуаций. Не осталась в стороне и среда Delphi. Обработка исключений была введена уже в Delphi 1.0, но, только начиная с Delphi 2.0, исключения стали частью Win32 API.
        В этой главе мы узнаем, что такое исключительная ситуация и как средствами Delphi можно ее обработать. Рассмотрим, что такое RTL-исключения, как можно использовать в обработке исключительных ситуаций метод TAppllcationHandleException. В данной главе мы познакомимся с интерфейсами. Подробно рассмотрим интерфейс IUnknown. А также рассмотрим, как можно использовать интерфейсы в распределенных приложениях.
        Понятие исключительной ситуации, ее обработка средствами Delphi
        Под исключительной ситуацией мы будем понимать некое непредвиденное событие, способное повлиять на дальнейшее выполнение программы.
        При обработке такой ситуации Delphi, как обычно, работает с объектами. С точки зрения компилятора Delphi исключительная ситуация — это объект. Для работы с этим специфичным объектом в Delphi (точнее, в Object Pascal) были введены следующие языковые конструкции: try .. except и try .. finally .
        Рассмотрим эти языковые конструкции более подробно.
        Итак, конструкция try .. except имеет следующий синтаксис (листинг 1.6):

        Если при выполнении кода, размещенного в разделе try, генерируется исключение, то выполнение этого раздела прекращается и управление передается коду, размещенному в разделе except. Раздел except может использоваться двумя способами. Во-первых, в нем могут располагаться любые операторы, кроме обработчиков исключений, начинающихся с приставки on. Это и операторы сообщения об ошибке, и команды, позволяющие освобождать системные ресурсы, а также другие операторы и команды. Во-вторых, раздел except используется для обработки исключений. В этом случае в него могут включаться только операторы обработки исключений. Если среди обработчиков встретился обработчик, соответствующий сгенерированному исключению, то выполняется оператор этого обработчика, исключение разрушается и управление передается коду, расположенному после оператора on Exception do. Раздел, расположенный после ключевого слова else, служит для обработки любых исключений, не описанных в разделе except. Этот раздел не является обязательным. Если при обработке исключительной ситуации не будет найден подходящий обработчик, то произойдет обработка системным обработчиком исключений.
        Рассмотрим простой пример обработки исключительной ситуации деления на ноль (листинг 1.7).

        Листинг 1.7
        try
        а:=10;
        b:=0;
        c:=a/b;
        except
        on EZeroDivide do MessageBox(‘Делить на ноль нельзя!’);
        end;

        Итак, как можно видеть из приведенного выше примера, для обработки разных исключений служат разные операторы. Рассмотрим более подробно оператор обработки on .. do . Данный оператор находится внутри раздела except и может иметь две формы (листинг 1.8).

        Листинг 1.8
        on do ;
        или
        on :
        do

        Этот оператор обрабатывает только тот класс исключений, который в нем указан. При указании родительского (базового) класса, все классы исключений — потомки данного класса — также будут обработаны. Для обработки всех исключений можно обратиться к базовому классу всех исключений: Exception. После обработки исключения оно разрушается. Вторая форма оператора on .. do отличается от первой тем, что данному исключению можно временно присвоить имя и обращаться к свойствам исключения. Обращаться к свойствам исключения можно с помощью конструкции . . Посмотрим листинг 1.9.

        Листинг 1.9
        try
        ScrollBarl.Max := ScrollBarl.Min — 1;
        except
        on E: EInvalidOperation do
        MessageDlg( ‘Игнорируем исключение: ‘- + E.Message, mtlnformation, [mbOK], O)
        end;

        В приведенном примере мы присваиваем исключению EInvalidOperation временное имя Е. Затем в окне сообщения выводим текст ошибки E.Message, выдаваемый Delphi по умолчанию (если бы не было нашего обработчика ошибки).

        Примечание
        Никогда не уничтожайте временный объект исключения. Обработчик исключений автоматически уничтожает объекты исключения. Если вы уничтожите объект исключения самостоятельно, это может привести к ошибке доступа.

        Иногда, бывает необходимо, чтобы после обработки исключительной ситуации своим кодом вызывался стандартный обработчик ошибки. Например, в случае возникновения некоторой ошибки вы хотите, чтобы приложение сообщало пользователю какую-либо информацию, а затем передавало управление стандартному обработчику ошибок. Как вы уже знаете, после обработки исключения вашим кодом, исключение уничтожается. Для того чтобы самостоятельно вызвать снова это исключение, можно воспользоваться регенерацией исключений. Для регенерации исключения служит команда raise. Рассмотрим листинг 1.10.

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

        Листинг 1.11
        try
        < операторы >except
        Application.HandieException(Self);
        end;

        Следующая конструкция try .. finally служит для защиты кода, записанного в разделе finally от исключительных ситуаций, которые в силу каких-либо причин могут происходить в разделе try. Синтаксис этой конструкции представлен на листинге 1.12.

        Итак, операторы, которые размещены после ключевого слова finally , будут выполняться в любом случае, была сгенерирована исключительная ситуация или нет. Если в разделе try была сгенерирована исключительная ситуация, то управление немедленно передается разделу finally . Также, если исключительной ситуации в разделе, try не было, блок finally будет выполняться. Даже если в разделе finally произойдет ошибка, выполнение операторов этого раздела будет продолжено до конца. В конструкции try .. finally не происходит обработка исключений, она используется в основмом для освобождения ресурсов памяти, закрытия ненужных файлов и других операций освобождения ресурсов. Таким образом, в данной конструкции нуждаются операции с файлами, памятью, ресурсами Windows и объектами.
        Код обработки исключения можно разбить на блоки try .. except .. end и try .. finally .. end. Эти блоки могут быть вложенными (рис. 1.24, а и б).
        При разработке приложений на Delphi часто возникают ситуации, когда программисту не требуется обрабатывать исключения, а необходимо лишь прервать нежелательное действие, вызывающее ошибку. Для этого применяются так называемые молчаливые исключения (silent exceptions). Молчаливые исключения являются потомками стандартного исключения EAbort . По умолчанию обработчик ошибок VCL Delphi отображает на экране диалоговое окно ошибки для всех исключений, кроме наследников EAbort.

        Примечание
        При создании консольных приложений сведения об ошибке выводятся и для необработанных исключений EAbort.

        Для того чтобы сгенерировать молчаливое исключение, можно вызвать процедуру Abort. Она автоматически сгенерирует исключение EAbort, которое прервет текущую операцию без вывода сведения об ошибке на экран. Рассмотрим пример. Пусть форма содержит пустой список (ListBoxi) и кнопку (Button1). Запишем в обработчик события кнопки onclick следующий код:

        Листинг 1.13
        procedure TForml.ButtonlClick(Sender: TObject);
        var
        I: Integer;
        begin
        for I := 1 to 10 do (цикл 10 раз>
        begin
        ListBoxl.Items.Add(IntToStr(I)); <добавляем номер в список>
        if I = 7 then Abort; <прерываем добавление номеров в список после добавления седьмого номера>
        end;
        end;

        В результате работы программы, после нажатия кнопки Button1, в список будет добавлено семь строк с номерами от 1 до 7.

        Рис. 1.24. Вложенные блоки в обработчике исключений (а) и в конструкции защиты кода (б)
        Обработка RTL-исключений. Иерархия исключений
        RTL (real time library)-исключения определены в модуле Delphi sysutils и являются наследниками базового класса исключений Exception.
        Имеется несколько типов исключений-наследников RTL (табл. 1.1).
        Таблица 1.1 . Типы исключений из RTL

        Ошибка доступа к файлу или устройству ввода/вывода

        Большинство исключений ввода/вывода связано с кодом ошибки, возвращаемом Windows при обращении к файлу

        Ошибка использования динамической памяти

        Ошибки кучи возникают при недостатке памяти или когда в приложении присутствует указатель на область памяти вне кучи

        Целочисленные математические операции

        Неправильное действие с выражением целого типа

        Ошибки включают в себя: деление на ноль, переполнение, выход за пределы диапазона и др.

        Математические операции с плавающей точкой

        Неправильное действие с выражением вещественного типа

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

        Неправильная работа с классами при помощи операции as

        Объекты могут работать только с совместимыми объектами

        Неправильное преобразование типов

        Функции преобразования типов (IntToStr, StrToInt И др.) генерируют эту ошибку в случае невозможности преобразования

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

        Неправильное использование типа

        Ошибка возникает в выражениях, где не может использоваться тип


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

        — базовый класс исключений

        — исключение для намеренного прерывания вычислений

        — попытка вызова абстрактного метода

        — ошибка доступа к памяти

        — ошибка при работе с массивами

        — ошибка при проверке истинности

        — ошибка доступа к массиву булевых величин TBits

        — ошибка построения кэша

        — ошибка регистрации или переименования компонента

        — нажатие пользователем клавиш + при выполнении консольного приложения

        — ошибка преобразования строк (объектов)

        — ошибка работы с базами данных

        — ошибка в наборе данных клиента

        — ошибка обновления данных компонента

        — генерируется компонентом TQuery при попытке открыть запрос без select

        — ошибка при обновлении В TProvider

        — ошибка ввода даты или времени

        — ошибка формата данных в кубе решений

        — ошибочный индекс в задании размерности в кубе решений

        — ошибка ввода/вывода в файл

        — базовый класс исключений целочисленных математических операций

        — ошибка деления на ноль

        — значение или индекс вне допустимого диапазона

        — ошибочное преобразование типов as к интерфейсу

        — нераспознаваемый графический файл

        — ошибка при операциях с графикой

        — ошибка при работе с сеткой (Grid)

        — ошибочная операция с компонентом

        — ошибка при операциях с указателем

        — ошибка при работе со списком

        — ошибка выделения памяти для куба решений

        — базовый класс исключений операций с плавающей запятой

        — недопустимое значение параметра при обращении к математической функции

        — потеря значащих разрядов

        — ошибка деления на ноль

        — ошибка доступа к устройствам через драйвер MCI (Media Control Interface)

        — ошибка при работе с элементами меню

        — ошибка при связывании приложения с элементом ActiveX

        — низкоуровневая ошибка OLE

        — ошибка интерфейса OLE IDispatch

        — ошибка OLE, связанная со свойством или методом

        — ошибка при работе с Tout line

        — ошибка распределения памяти

        — ошибка создания обработчика Windows

        — исключение, генерируемое при загрузке или использовании пакета

        — ошибка преобразования текста описания формы в двоичный формат

        — ошибка выполнения инструкции процессора из-за нехватки привилегий

        — ошибка записи с помощью OLE значения свойства, предназначенного только для чтения

        — ошибка чтения с помощью OLE значения свойства, предназначенного только для записи

        — ошибка при задании значения свойства

        — ошибка при работе с реестром Windows

        — ошибка задания типа сервера (компонент TReport не может соединиться с базой данных)

        — ошибка загрузки файла ресурсов (*.DFM или *.RES) во время создания приложения

        — переполнение стека — базовый класс исключений ошибок потоков

        — ошибка создания файла

        — ошибка открытия файла

        — базовый класс исключений файловых потоков

        — ошибка чтения заданного числа байт

        — ошибка записи заданного числа байт

        — ошибка связи компонента с приложением

        — ошибка чтения файла ресурсов

        — не найден метод

        — ошибка доступа к окну списка

        — ошибка многопоточного приложения

        — ошибка индекса при работе с TTreeview

        — ошибка при работе с типом данных variant

        — внутренняя ошибка Windows


        Итак, класс Exception является базовым классом всех исключений в Delphi. Все вышеописанные классы являются прямыми или косвенными наследниками класса Exception. При создании собственных новых классов исключений необходимо использовать класс Exception как родительский. Только в этом случае Delphi гарантированно распознает и обработает новый класс как исключение. В свою очередь, класс Exception является прямым наследником базового класса TObject, и наследует все его функции. В отличие от
        других классов, классы исключений начинаются не с буквы т, а с буквы Е. При создании собственных классов исключений можно называть их по своему усмотрению, не обязательно начиная с буквы Е (но это считается плохим стилем программирования).
        Создание собственных исключений
        Для создания собственных типов исключений необходимо знать, как определить тип объекта исключения, а также как вызвать исключение.
        Так как исключение является объектом Delphi, то определение нового типа исключения так же nporfro, как определение объекта нового типа. Теоретически возможно вызывать любой объект как объект исключения, но стандартные обработчики исключений работают только с теми объектами, предками которых являются Exception или потомки Exception.
        В качестве примера создания собственного типа исключения рассмотрим следующее определение:
        type
        EMyException = class(Exception);
        Теперь, если вы вызовете исключение EMyException, но не напишете обработчик для него, то произойдет вызов стандартного обработчика для Exception. Так как стандартный обработчик для Exception показывает имя вызванного исключения, вы можете увидеть имя вашего нового исключения.
        Для вызова созданного исключения используйте команду raise. Для примера рассмотрим типичную задачу проверки введенного пользователем пароля:
        type
        EPasswordlnval >
        После определения нового типа исключения EpasswordInwalid вы можете вызвать это исключение в любом месте программы:
        if Password <> CorrectPassword then raise EPasswordlnvalidCreate(‘Введен неправильный пароль’);
        Вызов созданного исключения производится по его имени.
        Интерфейсы и их совместное использование классами
        Ключевое слово Delphi interface позволяет создавать и использовать интерфейсы в ваших приложениях. Интерфейсы служат для расширения модели наследования в VCL, позволяя одному классу принадлежать нескольким
        интерфейсам, а также нескольким классам — наследникам различных базовых классов использовать один интерфейс. Интерфейсы полезны в тех случаях, когда наборы операций, такие как потоки, используются большим количеством объектов.
        Таким образом, интерфейсы — это средства для обеспечения взаимодействия между разными объектами.
        Интерфейсы являются фундаментом для технологий компонентной объектной модели (СОМ) и CORBA.
        Интерфейсы похожи на классы, которые содержат в себе только абстрактные методы и четкие определения их функциональности. Определение метода интерфейса включает в себя параметры и типы параметров, возвращаемый тип, а также ожидаемое поведение. Методы интерфейса семантически или логически связаны с отражением цели интерфейса. Существует соглашение об интерфейсах, гласящее, что каждый интерфейс должен быть назван в соответствии с задачей, которую он будет выполнять. Например, интерфейс iMalloc предназначен для распределения, освобождения и управления памятью. Аналогично, интерфейс IPersist может использоваться как базовый интерфейс для потомков, каждый из которых определяет специфичные прототипы методов для загрузки и сохранения состояния объектов в память, поток или в файл. Приведем простой пример объявления интерфейса (листинг 1.14):

        Листинг 1.14
        type
        IEdit = interface
        procedure Copy; stdcall;
        procedure Cut; stdcall;
        procedure Paste; stdcall;
        function Undo: Boolean; stdcall;
        end;

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

        Нельзя создать экземпляр интерфейса при помощи интерфейса. Для получения экземпляра интерфейса вам нужно объявить его в классе, содержащем данный интерфейс. Таким образом, нужно определить класс, который содержит необходимый интерфейс в списке своих родителей (листинг 1.15).

        Листинг 1.15
        TEditor = class(TInterfacedObject, lEdit)
        procedure Copy; stdcall;
        procedure Cut; stdcall;
        procedure Paste; stdcall;
        function Undo: Boolean; stdcall;
        end;

        Как уже было отмечено выше, использование интерфейсов позволяет нескольким классам использовать один интерфейс, игнорируя требование наличия одного базового класса-предка. Следует запомнить, что интерфейс — это тип с управляемым временем жизни, т. е., он автоматически, при инициализации, принимает значение nil, обладает счетчиком ссылок и автоматически уничтожается, при выходе за пределы своей области видимости.
        Интерфейс IUnknown
        По аналогии с наследованием классов, предком которых является базовый класс TObject, все интерфейсы — это прямые или косвенные наследники интерфейса IUnknown. Этот базовый интерфейс описан в модуле System следующим образом (листинг 1.16):

        Листинг 1.16
        type
        IUnknown = interface
        [‘< 00000000-0000-0000-С000-000000000046>‘]
        function Querylnterfасе(const IID: TGUID; out Obj): Integer; stdcall;
        function _AddRef: Integer; stdcall;
        function _Release: Integer; stdcall;7
        end;

        Синтаксис описания интерфейса похож на описание класса. Главное отличие заключается в том, что интерфейс может быть связан с глобальным уникальным идентификатором (Global Unique Identifier, GUID).
        GUID — это 128-разрядное целое число, которое используется для уникальной идентификации интерфейсов. Так как в 128-ми разрядах можно закодировать большое количество чисел, GUID практически гарантирует глобальную уникальность идентификатора интерфейса. То есть, практически невозможно, чтобы на двух компьютерах GUID совпал. Алгоритм генерации GUID основан на аппаратной части компьютера (частота процессора, номер сетевой карты и т. д.). В результате работы алгоритма, который может быть реализован с помощью функции API CocreateGUID (), получается запись типа TGUID. Эту запись можно определить в виде строки следующего формата:
        ‘<хххххххх-хххх-хххх-хххх-хххххххххххх>‘
        В дальнейшем, при рассмотрении СОМ, мы увидим, что каждый интерфейс или класс СОМ имеет собственный GUID. Для интерфейсов — это идентификатор интерфейса (Interface ID, IID), а для класса — идентификатор класса (Class ID, CLSID).
        Для создания нового GUID в среде Delphi достаточно нажать комбинацию клавиш + + в окне редактора кода.
        Итак, интерфейс lunknown поддерживает три метода, которые наследуются всеми интерфейсами:
        — QueryInterface() — используется для создания запроса, поддерживается ли данный интерфейс и если ответ положителен, то метод возвращает указатель на него. Для примера, предположим, что имеется некоторый объект object, который поддерживает несколько интерфейсов interface1, interface2 и др. Для получения указателя на интерфейс interface2, объекта Object, вам нужно вызвать метод Interface2.Query Interface О;
        — _AddRef () — используется, когда получен указатель на данный интерфейс и вы хотите работать с этим указателем. Метод _AddRef() обязательно должен заканчиваться вызовом метода _Release ();
        — _Release () — данный метод применяется для завершения работы с интерфейсом.
        Интерфейсы являются фундаментальными элементами таких распределенных объектных моделей, как СОМ и CORBA.
        Более подробно интерфейс lunknown мы рассмотрим в третьей части книги, посвященной использованию технологий СОМ и ActiveX.
        Класс TlnterfacedObject
        В VCL Delphi определен класс TlnterfacedObject, который служит базовым классом для объектов интерфейса. Данный класс определен в модуле Delphi system следующим образом (листинг 1.17):

        Листинг 1.17.
        type
        TlnterfacedObject = class(TObject, IUnknown) private
        FRefCount: Integer;
        protected
        function Querylnterface(const IID: TGUID; out Obj): Integer; stdcall;
        function _AddRef: Integer; stdcall;
        function _Release: Integer; stdcall; public
        property RefCount: Integer read FRefCount;
        end;

        Как мы видим, данный класс в качестве родителей имеет класс TObject и интерфейс lunknown. Класс Tinterfacedobject позволяет достаточно легко создавать классы, поддерживающие интерфейсы. Например,
        type
        TMyObjInterfaced = class(TInterfacedObject, IPaint)
        end;
        На вышеприведенном примере мы определяем новый класс TMyObj interfaced, который является прямым потомком класса Tinterfacedobject и поддерживает некий интерфейс IPaint.
        Использование оператора as
        Объекты, поддерживающие интерфейсы, могут использовать оператор as для динамического присоединения интерфейса. Например,
        procedurePaintObjecta(P: TInterfacedObject) var
        X: IPaint; begin
        X := P as IPaint;
        <операторы>
        end;
        В этом примере переменная Р имеет тип Tinterfacedobject. Данная переменная может быть назначена переменной х, как ссылка на интерфейс IPaint.. Для такого назначения компилятор генерирует код для вызова метода Querylnterface, относяшегося к Интерфейсу IUnknown переменной Р. Подобное назначение возможно, даже если Р не поддерживает данный интерфейс. То есть, компилятор не выдаст ошибку при таком назначении.
        Во время выполнения вышеприведенного примера либо успешно происходит присваивание
        Х:= Р as IPaint;
        либо генерируется исключительная ситуация.
        При использовании оператора as вы должны выполнять следующие требования:
        — при объявлении интерфейса, явно объявляйте в качестве предка интерфейс lunknown. Так как только в этом случае вы сможете воспользоваться оператором аs;
        — если вы используете оператор as для интерфейса, данный интерфейс должен иметь свой IID. Напомним, что для создания нового IID достаточно, находясь в редакторе кода, использовать комбинацию клавиш + + .
        Использование ключевого слова implements
        Многие классы VCL Delphi имеют в качестве некоторых своих свойств объекты. Кроме того, вы можете использовать в качестве свойств класса интерфейсы. В том случае, когда свойство имеет тип интерфейса, то вы можете использовать ключевое слово implements для определения методов, которые данный интерфейс передает объекту. По умолчанию, ключевое слово implements передает все методы интерфейса. Тем не менее, вы можете самостоятельно определить список тех методов интерфейса, которые передаются объекту.
        На приведенном ниже листинге 1.18 представлен пример использования ключевого слова implements при создании объекта адаптера цвета, предназначенного для преобразования восьмибитного значения цвета RGB.

        Листинг 1.18
        unit cadapt;
        interface
        uses
        Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;
        type
        IRGBSbit = interface
        [‘‘]
        function Red: Byte;
        function Green: Byte;
        function Blue: Byte;
        end;
        IColorRef = interface
        [41d76360b-f4f5-lldl-87d4-00c04fbl7199>’] function Color: Integer; end;
        TRGBSColorRefAdapter = class(TInterfacedObject, IRGBSbit, IColorRef) private
        FRGBSbit: IRGBSbit;
        FPalRelative: Boolean; public
        constructor Create(rgb: IRGBSbit);
        property RGBSIntf: IRGBSbit read FRGBSbit implements IRGBSbit;
        property PalRelative: Boolean read FPalRelative write-FPalRelative;
        function Color: Integer; end;
        implementation
        constructor TRGBSColorRefAdapter.Create(rgb: IRGBSbit);
        begin
        FRGBSbit := rgb; end;
        function TRGBSColorRefAdapter.Color: Integer;
        begin
        if FPalRelative then
        Result := PaletteRGB(RGBSIntf.Red, RGBSIntf.Green, RGBSIntf.Blue) else
        Result := RGB(RGBSIntf.Red, RGBSIntf.Green, RGBSIntf.Blue);
        end;
        end.

        Использование интерфейсов в распределенных приложениях
        Интерфейсы являются фундаментальным элементом распределенных объектных моделей СОМ и CORBA (более подробно о моделях читайте в третьей части книги). Delphi обеспечивает базовые классы для этих технологий, которые расширяют возможности объекта TInterfacedObject.
        Классы СОМ добавляют возможности использования фабрик классов и идентификаторов классов (CLSID). Фабрики классов отвечают за создание экземпляров классов посредством CLSID. В свою очередь, CLSID используются для регистрации и манипуляции классами СОМ. Классы СОМ, которые обладают и фабрикой класса, и идентификатором класса, называются CoClasses. CoClasses имеют преимущество перед Querylnterface по части поддержки новых версий интерфейсов. Новые версии старых интерфейсов автоматически становятся доступными для программ-клиентов. В приложе ниях СОМ разработчик может вносить правку в код интерфейса для улучшения работы приложения, не изменяя клиентской части кода.
        Другая распределенная технология называется CORBA (Архитектура Брокера Общих Объектных Запросов, Common Object Request Broker Architecture). Описание данной технологии не входит в эту книгу, заметим только, что она позволяет создавать приложения для взаимодействия с различными аппаратными или программными платформами. Так, клиентское приложение CORBA, работающее в операционной системе Windows 98, также легко будет работать с сервером приложений операционной системы UNIX.

        try-finally (Справочник по C#) try-finally (C# Reference)

        С помощью блока finally можно выполнить очистку всех ресурсов, выделенных в блоке try, и запускать код даже при возникновении исключения в блоке try . By using a finally block, you can clean up any resources that are allocated in a try block, and you can run code even if an exception occurs in the try block. Как правило, операторы блока finally выполняются, когда элемент управления покидает оператор try . Typically, the statements of a finally block run when control leaves a try statement. Передача управления может возникать в результате нормального выполнения, выполнения операторов break , continue , goto или return или распространения исключения из оператора try . The transfer of control can occur as a result of normal execution, of execution of a break , continue , goto , or return statement, or of propagation of an exception out of the try statement.

        Внутри обработанного исключения гарантируется выполнение связанного блока finally . Within a handled exception, the associated finally block is guaranteed to be run. Однако если исключение не обработано, то выполнение блока finally зависит от того, как запускается операция развертывания исключения. However, if the exception is unhandled, execution of the finally block is dependent on how the exception unwind operation is triggered. Это, в свою очередь, зависит от способа настройки компьютера. That, in turn, is dependent on how your computer is set up.

        Как правило, когда необработанное исключение приводит к завершению работы приложения, выполнение блока finally не имеет значения. Usually, when an unhandled exception ends an application, whether or not the finally block is run is not important. Однако если в блоке finally есть операторы, которые необходимо запускать даже в такой ситуации, одним из решений является добавление блока catch в оператор try — finally . However, if you have statements in a finally block that must be run even in that situation, one solution is to add a catch block to the try — finally statement. Кроме того, можно перехватить исключение, которое может создаваться в блоке try оператора try — finally выше в стеке вызовов. Alternatively, you can catch the exception that might be thrown in the try block of a try — finally statement higher up the call stack. То есть можно перехватить исключение в методе, который вызывает метод, содержащий оператор try — finally , или в методе, который вызывает этот метод, или в любом методе в стеке вызовов. That is, you can catch the exception in the method that calls the method that contains the try — finally statement, or in the method that calls that method, or in any method in the call stack. Если исключение не перехвачено, выполнение блока finally зависит от того, активирует ли операционная система операцию развертывания исключения. If the exception is not caught, execution of the finally block depends on whether the operating system chooses to trigger an exception unwind operation.

        Пример Example

        В следующем примере недопустимый оператор преобразования вызывает исключение System.InvalidCastException . In the following example, an invalid conversion statement causes a System.InvalidCastException exception. Исключение не обрабатывается. The exception is unhandled.

        В следующем примере исключение из метода TryCast перехватывается в методе выше в стеке вызовов. In the following example, an exception from the TryCast method is caught in a method farther up the call stack.

        Дополнительные сведения о finally см. в разделе try-catch-finally. For more information about finally , see try-catch-finally.

        C# также содержит оператор using, который предоставляет аналогичную функциональность для объектов IDisposable в удобном синтаксисе. C# also contains the using statement, which provides similar functionality for IDisposable objects in a convenient syntax.

        Спецификация языка C# C# language specification

        Дополнительные сведения см. в разделе Оператор try в документации Спецификация C# 6.0. For more information, see The try statement section of the C# language specification.

        Delphi-Help

        Try

        Описание

        Ключевое слово Try используется для отметки начала блока инструкций, которые перехватывают ошибки. Если происходит ошибка, программа не заканчивается. Вместо этого, управление передаётся или к Finally или Excep разделу.

        Try используется следующими способами:

        Версия 1:

        В конструкции Try-Finally, инструкция Finally гарантированно выполнится, абсолютно независимо оттого, что произойдет в предложении Try. Однако, предложение Finally фактически не обрабатывает никаких исключений — программа закончится, если никаких пунктов Except не найдено (см. примечания ниже).

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

        Версия 2:

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

        Версия 3:

        Она подобно версии 2, но определяет различные действия для различных типов исключений, таких как EInOutError. Пункт Else может использоваться как ловушка всех неопределенных типов исключений. Общий тип исключений Exception может использоваться для захвата всех типов исключений.

        По назначенному имени (Name) исключения, можно получить текст сообщения исключения (Name.Message) для его отображения или других использований.

        Если исключение не обработано инструкциями On или Else (для 3 версии), то выполняется проверка, находимся ли мы во вложенном блоке Try. Если да, то обрабатывается пункт Except своего родительского Try.

        Пункт Else не является, действительно необходимым, лучше использовать On E:Exception Do являющееся универсальной обработкой особых ситуаций, так как обеспечивает сообщение об ошибке (E.Message).

        Важно: вы можете определить тип ошибки, которая произошла, при использовании универсальной обработки особых ситуаций — On E:Exception Do. E это указатель на объект исключения. E.ClassName дает тип исключения, такой как ‘EDivByZero‘, как показано в последнем примере.

        Следующий список исключений охватывает основные типы — всего имеется сотни классов исключения:

        Exception Базовый класс
        EAbort Аварийное завершение работы без диалогового окна
        EAbstractError Абстрактная ошибка метода
        AssertionFailed Утверждают неудавшийся запрос
        EBitsError Булев массив ошибок
        ECommonCalendarError Календарная ошибка
        EDateTimeError Ошибка DateTime
        EMonthCalError Ошибка месяца
        EConversionError Вызывается Convert
        EConvertError Ошибка конвертирования объекта
        EDatabaseError Ошибка базы данных
        EExternal Ошибка аппаратных средств/Windows
        EAccessViolation Нарушение прав доступа
        EControlC Произошло аварийной завершение работы пользователем
        EExternalException Другая Внутренняя ошибка
        EIntError Целочисленная ошибка
        EDivByZero Деление на ноль
        EIntOverflow Переполнение целого числа
        ERangeError Вне диапазона значений
        EMathError Ошибка с плавающей запятой
        EInvalidArgument Плохое значение аргумента
        EInvalidOp Несоответствующая операция
        EOverflow Значение слишком большое
        EUnderflow Значение слишком маленькое
        EZeroDivide Деление на ноль
        EStackOverflow Серьёзная проблема Delphi
        EHeapException Проблемы динамической памяти
        EInvalidPointer Плохой указатель памяти
        EOutOfMemory Нет возможности распределить память
        EInOutError Ошибка ввода/вывода
        EInvalidCast Ошибка произведенная объектом
        EInvalidOperation Плохая операция компонента
        EMenuError Ошибка пункта меню
        EOSError Ошибка операционной системы
        EParserError Ошибка синтаксического анализа
        EPrinter Ошибка принтера
        EPropertyError Ошибка свойства класса
        EPropReadOnly Недопустимое обращение к свойству
        EPropWriteOnly Недопустимое обращение к свойству
        EThread Ошибка потока
        EVariantError Различная ошибка

        Пример кода

        var
        number, zero : Integer;
        begin
        // Попытка деленя целого числа на нуль — чтобы поднять исключение
        number := -1;
        Try
        zero := 0;
        number := 1 div zero;
        ShowMessage(‘number / zero = ‘+IntToStr(number));
        finally
        if number = -1 then
        begin
        ShowMessage(‘Числу не было присвоено значение — использование значения по умолчанию’);
        number := 0;
        end;
        end;
        end;

        Числу не было присвоено значение — использование значения по умолчанию

        Затем, программа заканчивается с сообщением об ошибке EDivByZero -, предложение finally не выловило ошибку.

        var
        number, zero : Integer;
        begin
        // Попытка деленя целого числа на нуль — чтобы поднять исключение
        Try
        zero := 0;
        number := 1 div zero;
        ShowMessage(‘number / zero = ‘+IntToStr(number));
        except
        ShowMessage(‘Неизвестная ошибка’);
        end;
        end;

        var
        number, zero : Integer;
        begin
        // Попытка деленя целого числа на нуль — чтобы поднять исключение
        Try
        zero := 0;
        number := 1 div zero;
        ShowMessage(‘number / zero = ‘+IntToStr(number));
        except
        on E : Exception do
        ShowMessage(E.ClassName+’ поднята ошибка, с сообщением : ‘+E.Message);
        end;
        end;

        EDivByZero поднята ошибка, с сообщением : Division by zero

        Примечание

        Иногда Вы хотите построить конструкцию подобно этому:

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

      6. Илон Маск рекомендует:  MySQL regexp регулярные выражения в mysql
    Понравилась статья? Поделиться с друзьями:
    Кодинг, CSS и SQL