End;
Except
on EMatchError do begin
Try try end;
End;
End
End;
16.1.2. Класс Exception
Класс Exception является родительским классом для всех классов-исключений. Этот класс объявляется в модуле sysUtils следующим образом:
Type
Exception = class(TObject)
Private
FMessage: String;
FHelpContext: Integer;
Public
constructor Create(const Msg: Strings);
constructor CreateFmt(const Msg: String;
const Args: array of const);
constructor CreateRes(Ident: Integers);
constructor CreateResFmt(Ident: Integer;
const Args: array of const);
constructor CreateHelp(const Msg: String; aHelpContext:
Integer);
constructor CreateFmtHelp(const Msg: String;
const Args: array of const; aHelpContext: Integers);
constructor CreateResHelp(Ident: Integer; aHelpContext:
Integer);
constructor CreateResFmtHelp(Ident: Integer;
const Args: array of const;
aHelpContext: Integers);
property HelpCoatext: Integer read FHelpContext write FHeipContext;
property Message: String read FMessage write FMessage;
End;
В классе определены целых 8 конструкторов для создания объекта. С их помощью можно прочитать текстовое сообщение из ресурса, отформатировать его, связать исключение с контекстной справочной службой. Свойство Message делает доступным частное поле FMessage, в котором содержится текстовое сообщение.
16.1.3. Стандартные классы исключений
В Delphi определены стандартные классы исключений, перечисленные в табл. 16.1. Именно эти имена, а также имена пользовательских классов (см. п. 16.1.5) могут использоваться в обработчиках исключении.
Таблица 16.1
Класс
| Родитель
| Обрабатываемое исключение
|
EAbort
| Exception
| Реализует “тихую” (без какого-либо сообщения) обработку любого исключения
|
EAbstractErrpr
| Exception
| Программа пытается вызвать абстрактный метод
|
EAccessViolation
| Exception
| Программа пыталась обратиться к не принадлежащей ей области памяти или использует недействительный указатель
|
EAppletException
| Exception
| Ошибка связана с созданием управляющих панелей в апплет-приложениях
|
EArrayError
| Exception
| Возникает из-за различного рода ошибок при работе с массивами (неверный индекс, попытка вставить элемент в массив фиксированной длины или в отсортированный массив и т. п.)
|
EAssertionFaild
| Exception
| Возбуждается отладочной процедурой Assert, когда тстируемое ею логическое выражение имеет значение False.
|
EBitsError
| Exception
| Программа пыталась обратиться к свойству Bits объекта TBits с индексом меньше нуля или больше максимально допустимого значения
|
EBrokerException
| Exception
| Объект-брокер не может найти сервер
|
ECacheError
| Exception
| Ошибка в наборе данных для компонента Tde-cisionCube
|
EClassNotFound
| EFilerError
| Для компонента, читаемого из потока данных, не найден соответствующий класс. Обычно возникает"в случае, когда в форму вставлен нестандартный компонент, а в библиотеке компонентов Delphi нет связанного с ним класса
|
ECommonCalendar-Error
| Exception
| Возникает в объектах класса TCommonCalendar и его потомках, когда вводится неверная дата
|
EComponentError
| Exception
| Возникает при различных манипуляциях программы с компонентом (программа не может зарегистрировать компонент, переименовать его или когда для его работы требуется интерфейс СОМ, который компонентом не поддерживается)
|
EControlC
| Exception
| Возникает при нажатии Ctrl-C при работе приложения в режиме консолиЛ
|
EConvertError
| Exception
| Ошибка преобразования в функциях StrToint или StrToFloat
|
ECorbaDispatch
| Exception
| Возникает в программах, использующих технологию corba, при ошибках, связанных с несовпадением интерфейсов сервера и брокера данных
|
ECorbaException
| Exception
| Возникает в программах, использующих технологию CORBA
|
ECorbaUser-Exception
| ECorbaException
| Возникает как определяемая пользователем реакция на ошибки интерфейса
|
EDatabaseError
| Exception
| Возникает, когда компонент обнаруживает ошибку в базе данных
|
EDateTimeError
| Exception
| Возбуждается компонентом TDateTimePicker при попытке ввода неверной даты или времени
|
EDBClient
| EDatabaseError
| Ошибка связана с неправильной работой Tcli-entDataSet
|
EDBEditError
| Exception
| Возникает, когда компонент пытается использовать данные, несовместимые с заданной маской
|
EDBEngineError
| EDatabaseError
| Связана с ошибками BDE
|
EDimensionMar-Error
| Exception
| Возникает, когда используемый в кубе решений набор данных не имеет агрегатных полей
|
EDimIndexError
| Exception
| Связана с нарушением размерности массива данных для куба решений
|
EDivByZero
| EIntError
| Ошибка целочисленного деления на ноль
|
EDSWriter
| Exception
| Ошибка при подготовке провайдером пакета данных для набора данных
|
EExternal-Exception
| EStream-Error
| Возникла ошибка, код которой не является предопределенным в Delphi
|
EFCreateError
| EStream-Error
| Ошибка при создании файла. Например, попытка создать файл на устройстве, предназначенном только для чтения, или в несуществующем каталоге
|
EFilerError
| EStream-Error
| Программа пытается повторно зарегистрировать в потоке один и тот же класс
|
EFOpenError
| EStream-Error
| Ошибка открытия потока данных. Например, попытка открыть несуществующий файл
|
EHeapException
| Exception
| Ошибка связана с неправильными операциями над динамической памятью
|
ElBClientError
| ElBError
| Ошибка связана с функционированием IBX-клиента
|
ElBError
| EDatabaseError
| Общая ошибка технологии IBX
|
ElBInterbase-Error
| ElBError
| Ошибка связана с функционированием сервера в технологии IBX
|
EInOutError
| Exception
| Любая ошибка в файловых операциях. Поле ErrorCode объекта этого класса содержит код ошибки
|
EInterpreterError
| Exception
| Возникает, когда компонент класса TDataBlockinterpeter не может интерпретировать данные блока данных
|
EIntError
| Exception
| Любая ошибка в целочисленных вычислениях
|
EIntfCastError
| Exception
| Попытка недопустимого приведения типов в OLE-объектах
|
EIntOverflow
| EIntError
| Ошибка целочисленного переполнения: программа пытается присвоить целочисленной переменной значение, выходящее из 32-двоичных разрядов
|
EInva1i dArgument
| EMatchError
| Возбуждается математическими функциями при выходе аргумента из допустимого диапазона
|
EInvalidCast
| Exception
| Программа пытается осуществить недопустимое преобразование типов с помощью оператора as
|
EInvalidGraphic
| Exception
| Программа пытается загрузить в контейнер изображение из файла, который имеет недопустимый формат (допустимыми форматами являются растр, метафайл, курсор, пиктограмма)
|
EInvalidGraphic-Operation
| Exception
| Программа пытается выполнить недопустимую графическую операцию
|
EInvalidGrid-Operation
| Exception
| Программа пытается выполнить недопустимую операцию над таблицей (например, обратиться к несуществующему столбцу или РЯДУ)
|
EInvalidImage
| EFilerError
| Программа пытается прочитать ресурс изображения из файла, в котором этого ресурса нет
|
EInvalidOp
| EMatchError
| Ошибка в операциях с плавающей точкой (недопустимая инструкция, переполнение стека сопроцессора и т. п.)
|
EInvalidOpera-tion
| Exception
| Не имеющий окна компонент пытается выполнить операцию, требующую дескриптора окна
|
EInvalidPointer
| EHeap-Exception
| Попытка использовать недействительный указатель
|
EListError
| Exception
| Эта ошибка связана с неверными действиями программы по отношению к разного рода спискам. Например обращение к элементу списка с индексом меньше нуля или больше максимально допустимого
|
ELowCapacity-Error
| Exception
| Ошибка возникает при попытке выделения памяти на устройстве, у которого нет нужной свободной памяти.
|
EMatchError
| Exception
| Любая ошибка при выполнении вычислений с плавающей точкой.
|
EMenuError
| Exception
| Ошибка при работе программы с меню. Например, при добавлении элемента с идентификатором, который уже определен в меню
|
EMCIDiviceError
| Exception
| Ошибка возникла в медиаплейере
|
EMethodNotFound
| EFilerError
| Программа прочитала из потока данных объект, но не может найти связанный с классом объекта метод
|
EMonthCalError
| ECommon-Calendar-Error
| Возбуждается компонентом класса TMonthcal-endar при попытке ввода неправильной даты
|
EOleCtrlError
| Exception
| Программа не может установить связь с элементом ActiveX
|
EOleError
| Exception
| Низкоуровневая ошибка в технологии OLE
|
EOleException
| EOleSysError
| Программа использует неверный OLE-интерфейс
|
EOleRegistration Error
| EOleError
| Ошибка регистрации OLE-объекта в реестре Windows
|
EOleSysError
| EOleError
| Возникает при неправильном выполнении команды OLE автоматизации
|
EOutlineError
| Exception
| Возникает при ошибке доступа к компоненту класса ToutLine
|
EOutOfMemory
| EHeap-Exception
| Эта ошибка возникает, когда программа запрашивает слишком большой для данной конфигурации Windows объем памяти
|
EOutOfResource
| EOutOfMemory
| Программа требует от Windows дескриптор окна, но Windows исчерпала лимит дескрипторов
|
EOverflow
| EMatchError
| Результат операций с плавающей точкой слишком велик, чтобы уместиться в регистрах сопроцессора
|
EPackageError
| Exception
| Возникает при ошибке доступа к пакету
|
EParserError
| Exception
| Ошибка преобразования текста в двоичные данные при чтении из потока
|
EPrinter
| Exception
| Windows сообщила программе об ошибке принтера
|
EPrivilege
| Exception
| Программа пытается выполнить привилегированную операцию. Привилегированные операции могут выполняться только ядром Windows
|
EPropertyConvert Error
| Exception
| Ошибка при чтении или записи значения свойства
|
EPropertyError
| Exception
| Ошибка доступа к свойству при чтении или записи
|
EPropReadOnly
| Exception
| Программа пытается присвоить значение свойству, из которого можно только читать (при использовании технологии OLE)
|
EPropWriteOnly
| Exception
| Программа пытается прочитать свойство, предназначенное только для записи
|
ERangeError
| EIntError
| Целочисленный результат превышает емкость целого типа данных
|
EReadError
| EFilerError
| Программа не может прочитать из потока данных нужного количества байт
|
EReconcileError
| EData-baseError
| Ошибка обновления данных в TclientDataset
|
ERegistry-Exception
| Exception
| Ошибка, связанная с операцией над реестром Windows
|
EResNotFound
| Exception
| Программа не может найти указанный ресурс в файле ресурсов
|
ESocketConnec-tionError
| Exception
| Ошибка связана с работой с сокетами Windows
|
ESocketError
| Exception
| Ошибка связана с работой с сокетами Windows
|
EStackOverflow
| Exception
| Исчерпан объем выделенного программе стека
|
EStreamError
| Exception
| Любая ошибка при работе с потоком данных
|
EStringListError
| Exception
| Программа ссылается на строку, индекс которой выходит из диапазона возможных значений для списка строк
|
EThread
| Exception
| Ситуация борьбы за общий ресурс в программе с несколькими потоками команд
|
ETreeViewError
| Exception
| Указан неверный индекс при обращении к
TtreeView
|
EUnderflow
| EMatchError
| Результат операций с плавающей точкой слишком мал, чтобы уместиться в регистрах сопроцессора (исчезновение порядка)
|
EUnsupportedTypeE rror
| Exception
| Выбран недопустимый тип поля в качестве измерения в кубе решений
|
EUpdateError
| Exception
| Ошибка обновления провайдерского набора данных
|
EVariantError
| Exception
| Ошибка при работе с типом Variant: недопустимое приведение типов; недопустимая операция; обращение -к скалярной переменной как к варианту-массиву; индекс варианта-массива выходит из допустимых значений
|
EWin32Error
| Exception
| Ошибочное обращение к API-функции Windows. Свойство Message содержит номер ошибки и связанное с ней сообщение
|
EWriteError
| EFilerError
| Ошибка записи в поток данных
|
EZeroDivide
| EMatchError
| Вещественное деление на ноль
|
Важно помнить, что ищется самый первый из, возможно, нескольких обработчиков, класс которого способен обрабатывать данное исключение. Если, например, в списке первым стоит EAbort, который может обработать любое исключение, ни один из стоящих за ним обработчиков никогда не получит управления. Точно так же, если указан обработчик для класса EintError, за ним бесполезно размещать ОбработчикиEDivByZero, ERangeErrorили EIntOverflow:
Try
Except
// He имеет смысла делать так:
on EintError do.....;
on ERangeError do.....;
on EDivByZero do.....;
// Надо так:
on ERangeError do.....;
on EDivByZero do.....;
on EintError do.....;
End;
При возникновении исключительной ситуации объекты классов-обработчиков создаются и уничтожаются автоматически. Если программист пожелает использовать поля или методы класса-обработчика явно, он должен поименовать автоматически создаваемый объект. Для этого перед именем класса ставится идентификатор и двоеточие:
on EObject: EClassName do.....;
Для стандартных классов такой прием фактически позволяет использовать единственное строковое свойство Message со стандартным сообщением об ошибке, которое получают все наследники класса Exception. Исключение составляет класс EInOutError, в котором для программиста может представлять интерес целочисленное свойство ErrorCode с кодом ошибки ввода/вывода.
Например:
Reset(F);
while not EOF(F) do begin
End;
CloseFile(F);
Except
on E: EInOutError do
ShowMessage('При выполнении файловой операции возникла'+ ' ошибка №'+ IntToStr(E.ErrorCode));
End;
16.1.4. Вызов исключения
В некоторых ситуациях программисту бывает необходимо инициировать собственное исключение. Для этого он использует зарезервированное слово raise (возбудить). Если это слово встретилось в секции try...exception или try...finally, немедленно начинают свою работу секции соответственно except... end и finally... end. Если оно встретилось в except...end или finally...end, считается, что данный защищенный блок на текущем уровне вложенности (блоки могут быть вложенными) завершил свою работу и управление передается вышестоящему уровню.
Слово raise возбуждает исключение самого общего класса Exception. Если программист желает возбудить исключение конкретного типа (не важно - стандартного или собственного), он должен явно указать класс создаваемого в этот момент объекта путем вызова его конструктора. Например, следующий оператор возбудит ошибку ввода/вывода:
raise EInOutError.Create('Ощибка!');
Такой прем - единственная возможность возбудить нестандартное исключение, обрабатываемое пользовательским классом.
16.1.5. Создание собственного класса
Программист может создать собственный класс обработки исключений, объявив его потомком Exception или любого другого стандартного класса (этим другим чаще всего бывает класс EAbort). Объявление нестандартного класса имеет смысл только тогда, когда вам необходимо научить программу распознавать некорректные наборы данных и соответствующим образом на них реагировать.
Пусть, например, в программе используется цикл ввода целочисленных значений из текстового файла, их проверки и преобразования. Проверка заключается в простом контроле неотрицательности очередного числа после ввода и его положительности после преобразования. Перед проверкой необходимо получить строку из файла (здесь может возникнуть ошибка EinOutError) и преобразовать ее в целую величину (здесь возможна ошибка EConvertError); после проверки осуществляется обработка величины, в процессе которой может возникнуть ошибка EIntError.
Создадим новый класс EIntCheckError и будем возбуждать исключение этого класса при обнаружении ошибки в данных:
Type
EIntCheckError = class(EAbort)
end;
Var
F: TextFile;
S: String;
k: Integer;
begin
Try
// Готовимся к работе: открываем файл AssignFile(F, FileName);
Reset(F); // Здесь возможна ошибка EinOutError // Цикл ввода-контроля-преобразования while not EOF(F) do begin
// Вводим символы очередного числа
ReadLn(F,S);// Здесь возможна ошибка EinOutError
// Преобразуем символы в число
k:= StrToInt(S); // Здесь возможна ошибка EConvertError
// Проверяем число
if k < 0 then
raise EIntCheckError.Create("Отрицательное число');
// Преобразуем число
..... // Здесь возможна ошибка EIntError
// Вновь проверяем число
if k <= 0 then
raise EIntCheckError.Create('He положительное число');
End;
Except
on E: EIntCheckError do
ShowMessage(E.Message);
on EInOutError do
ShowMessage('Некорректная файловая операция');
on EConvertError do
ShowMessage('Ошибка в записи числа');
on EIntError do
ShowMessage('Ошибка преобразования');
End;
End;
В этом примере создается класс EIntCheckError, который ничем, кроме названия, не отличается от своего родителя EAbort. В реальной программе потомок обычно расширяет набор полей (свойств) своего родителя или перекрывает его методы; приведенный пример лишь иллюстрирует, что делать это необязательно. При неудачной проверке операторами
raise EIntCheckError.Create('Отрицательное число');
и
raise EIntCheckError.Create('Ошибка преобразования');
возбуждается исключение нового класса. При этом с помощью унаследованного конструктора create создается новый безымянный объект, а строковый параметр обращения к конструктору запоминается в поле FMessage и становится доступен с помощью свойства Message объекта. Обработчик исключения EIntCheckError именует объект идентификатором e и с помощью стандартной процедуры ShowMessage показывает его в небольшом окне на экране.
Пример наглядно показывает выгоды использования исключений. В принципе весь этот фрагмент можно было бы написать с многочисленными проверками if... then, но в этом случае логика программы стала бы запутанной, а сама программа - сложной в отладке.