Тверской государственный университет
Опубликован: 13.09.2006 | Доступ: свободный | Студентов: 3491 / 369 | Оценка: 4.65 / 4.29 | Длительность: 30:37:00
Специальности: Программист, Менеджер
Лекция 11:

Отладка и оптимизация программ. Отладка

Оператор Resume

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

Resume [0]
Resume Next
Resume строка

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

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

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

Объект Err

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

Таблица 10.1. Описание свойств объекта Err
Свойство Значение
Number Номер (код) ошибки. Это свойство по умолчанию.
Source Строковое выражение, представляющее источник, в котором возникла ошибка. При ошибках в стандартном модуле оно содержит имя проекта. При ошибках в модуле класса свойство Source получает имя вида проект.класс. Конечно, хотелось бы, чтобы Source указывал источник возникновения ошибки более точно, хотя бы с точностью до имени процедуры, а лучше бы до оператора. Однако, этого пока не сделано.
Description Строка с кратким описанием ошибки, если такая строка для кода, указанного в Number, существует. Для собственных ошибок значение этого свойства следует задавать.
HelpFile Полное имя (включая диск и путь) файла справки VBA. Опять таки для собственных ошибок следует подготовить справочную систему и задавать путь к ней в этом свойстве.
HelpContext Контекстный идентификатор файла справки, соответствующий ошибке с кодом, указанным в свойстве Number.
LastDLLError Содержит системный код ошибки для последнего вызова DLL. Значение свойства LastDLLError доступно только для чтения. В лекции, посвященной работе с функциями Win32 API, подробно рассматривалось использование этого свойства.

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

Public Function Fact2(ByVal N As Integer) As Integer
	'Функция спроектирована для вычисления факториалов чисел, не больших 7
	#If conDebug Then
		Debug.Assert (N >= 0) And (N < 8)
	#End If
		
	If (N = 0) Or (N = 1) Then	 ' базис индукции.
		Fact2 = 1		' 0! =1.
	Else	' рекурсивный вызов в случае N > 0.
		Fact2 = Fact2(N - 1) * N
	End If
	
	#If conDebug Then
		Debug.Assert Fact2 <= 5040
	#End If
	
End Function

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

Public Sub TestFact2()
	Dim Msg As String
	Dim VictoryCount As Integer, Prize As Long
	On Error GoTo ErrHandler1
		VictoryCount = 5
		Prize = Fact2(VictoryCount) * 5
		Debug.Print VictoryCount, Prize
		
		VictoryCount = 10
		Prize = Fact2(VictoryCount) * 5
		Debug.Print VictoryCount, Prize
		
	Exit Sub
ErrHandler1:
	Msg = "Ошибка # " & Err.Number & " возникла в " & Err.Source _
		& vbCrLf & " Описание: " & Err.Description _
		& vbCrLf & " HelpFile: " & Err.HelpFile _
		& vbCrLf & " HelpContext: " & Err.HelpContext
	MsgBox Msg, vbMsgBoxHelpButton, "Error", Err.HelpFile, Err.HelpContext
	'Грубое устранение причин ошибки
	Err.Clear
	If VictoryCount < 0 Then VictoryCount = 0
	If VictoryCount > 7 Then VictoryCount = 7
	Resume
	
End Sub
10.3.

Вот как выглядит окно сообщения, выведенное в обработчике ошибки.

Сообщение, сформированное в обработчике ошибки

Рис. 10.16. Сообщение, сформированное в обработчике ошибки

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

5		 600 
7		 25200

Объект Err специально спроектирован для работы на этапе обнаружения и исправления ошибок периода выполнения. Он заменил ранее существовавшие функцию и оператор Err. Для совместимости с ними свойство Number реализовано, как свойство по умолчанию и его можно не указывать. Если в борьбе с ошибками на этапе отладки важную роль играет объект Debug, то не менее важна роль объекта Err при борьбе с ошибками периода выполнения. Также как и объект Debug, объект Err имеет всего два метода - Clear и Raise. Рассмотрим их подробнее.

Метод Clear

Его синтаксис:

Err.Clear

Этот метод используется для явной очистки значений свойств объекта Err после завершения обработки ошибки. Автоматическая очистка свойств Err происходит также при выполнении операторов:

  • оператора Resume любого вида;
  • Exit Sub, Exit Function, Exit Property ;
  • оператора On Error любого вида.
Метод Raise

Метод Raise генерирует ошибку выполнения. У него двоякое назначение. Во-первых, он используется для моделирования стандартных, внутренних ошибок. Необходимость в этом возникает, например, при отладке обработчиков соответствующих ошибок. Но его главное назначение состоит в возбуждении собственных ошибок, когда в результате проделанного анализа обнаружена исключительная ситуация. Его синтаксис:

Err.Raise number, source, description, helpfile, helpcontext

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

Параметр Number имеет тип Long и определяет код ошибки. Коды ошибок (как внутренних, так и определяемых пользователем) лежат в диапазоне 0-65535. При этом коды от 0 до 512 зарезервированы за системными ошибками VBA. При возбуждении собственных ошибок при задании параметра Number к ее собственному коду необходимо добавлять константу vbObjectError + 512, что позволяет системе отличать внутренние и пользовательские ошибки.

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

Класс и обработка ошибок

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

Option Explicit

'Класс Day
'Свойства класса
Private today As Date
Private temperature As Integer


Public Property Get Сегодня() As Date
	Сегодня = today
End Property

Public Property Let Сегодня(ByVal NewValue As Date)
	today = NewValue
End Property

Public Property Get Температура() As Integer
	Температура = temperature
End Property

Public Property Let Температура(ByVal NewValue As Integer)
	temperature = NewValue
End Property

Public Sub CheckDay()
	Dim Desc As String
	Dim Numb As Long
	Dim Source As String
	'Проверка свойств объекта
	Select Case Month(Сегодня)
		Case 6 To 8
			If Температура < 0 Then
				'Исключительная ситуация
			Desc = "Ошибка: Работа с объектом предполагает положительную 
			летнюю температуру!"
			Numb = vbObjectError + 513
			Source = " Метод CheckDay класса Day "
			Err.Raise Numb, Source, Desc
			End If
		Case 1 To 2, 12
			If Температура > 0 Then
				'Исключительная ситуация
			Desc = "Ошибка: Работа с объектом предполагает отрицательную 
			зимнюю температуру!"
			Numb = vbObjectError + 514
			Source = " Метод CheckDay класса Day "

			Err.Raise Numb, Source, Desc
			End If
	 End Select
End Sub
10.4.

Приведем теперь процедуру, работающую с объектами, этого класса:

Public Sub WorkWithDay()
	'Работа с объектами класса Day
	Dim myday As New Day
	Dim Msg As String
	'Охраняемый блок
	On Error GoTo ErrorHandler
	
		myday.Сегодня = "9.8.99"
		myday.Температура = -15
		myday.CheckDay
		Debug.Print myday.Сегодня, myday.Температура
	Exit Sub
ErrorHandler:
	If Err.Number = vbObjectError + 513 Then
		Msg = vbCrLf & "Введите температуру сегодняшнего дня " _
			& myday.Сегодня & vbCrLf & " Учтите, она должна быть 
			положительной"
		myday.Температура = InputBox(Err.Source & vbCrLf & 
		Err.Description & Msg, "CheckDay", 15)
	ElseIf Err.Number = vbObjectError + 514 Then
		Msg = vbCrLf & "Введите температуру сегодняшнего дня " _
			& myday.Сегодня & vbCrLf & " Учтите, она должна быть 
			отрицательной"
		myday.Температура = InputBox(Err.Source & vbCrLf & 
		Err.Description & Msg, "CheckDay", -15)
	End If
	Resume
End Sub
10.5.

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

Окно диалога с пользователем

Рис. 10.17. Окно диалога с пользователем

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

09.08.99    25
полина есенкова
полина есенкова
Дмитрий Вологжин
Дмитрий Вологжин
Добрый день, прошел тесты с 1 по 9, 10 не сдал, стал читать лекцию и всё пройденные тесты с 1 по 9 сбросились, когда захотел пересдать 10 тест.