On Error Resume Next'Вообще отключена обработка ошибок.On Error GoTo <метка>
'Твой обработчик ошибок.On Error GoTo 0
'Обработка ошибок по умолчанию. Используется для отключения предыдущих конструкций.
Конструкция нужна за тем, чтобы после строки кода, где возможно ее возникновение вставить код с обработкой ошибки:
If Err <> 0 Then
WScript.Echo "Error #" & Err.Number & " " & Err.Description
' Здесь можно что-то предпринять ...
WScript.Quit
End If
Здравствуйте, valmond, Вы писали:
V>Кто-то может внятно объяснить зачем в VB существует конструкция
V>On Error Resume Next
Это эквивалент такого обработчика ошибок:
On Error GoTo ErrorHandlerUseless
. . .
ErrorHandlerUseless:
Resume Next
V>Что за ситуация, когда нам пофигу есть ошибка или нет, и мы идем дальше?
VB будет ВСЕГДА реагировать на наличие ошибки, а мы должны реагировать на его реакцию. Если не реагировать, то задача, скорее всего, будет снята.
V>Лучше бы этой кострукции вообще небыло.
Я практически никогда неиспользую On error goto [Label], по причине того, что это не СТРУКТУРНЫЙ оератор. Практически всегда обработку я выполняю в стиле
On error Resume Next
err.Clear
...
if Err<>0 then
Err.Clear
...
end if
On Error Goto 0
Неструктурность On Error заключается в том, что я не знаю, что следует написать вместо On Error Goto 0 для восстановления предыдущего обработчика. Надо смотреть код выше. А если там есть что-то типа
if .... Then
On error Goto туда
else
On error goto сюда
end if
то это вообще отпад (а VB такое волне допускает). Попробуйте сдетать такое со структурными try / catch.
Уж лучше пользоваться обработкой оштюок в стиле C, чем On error goto.
Кроме того, некоторые методы VB вызывают Error когда их об этом не просят. Например SetFocus для невидимого аргумена вызывает ощибку. Спасибо! Практически всегда я пишу
on error resume next
Command1.SetFocus
err.Clear
on error goto 0
Здравствуйте, valmond, Вы писали:
V>Кто-то может внятно объяснить зачем в VB существует конструкция
V>
V>On Error Resume Next
V>
V>Что за ситуация, когда нам пофигу есть ошибка или нет, и мы идем дальше?
Ну например, необходимо написать следующую процедуру:
' Постараться выполнить во чтобы то ни стало критические действия
' Является порцедурой из-за того, что вызывающий не в курсе подробностей
' выполняемых действий, поэтому не сможет обработать ошибок
' Сама не обрабатывает ошибок, т.к. не особо в курсе вызываемых функций и методовPublic Sub PerformCriticaloperations()
On Error Resume Next
SomeOperation1
...
Someoperation2
...
SomeObject.Operation3
End Sub
Таким образом мы выполним максимальное количество действий, не задумываясь об их устройстве.
Я согласен, что в общем случае это — плохой стиль. Но когда работаем с объектами, в природе которых не очень разбирамся, наверное, — наилучший.
Здравствуйте, al, Вы писали:
al>Я практически никогда неиспользую On error goto [Label], по причине того, что это не СТРУКТУРНЫЙ оератор. Практически всегда обработку я выполняю в стиле
al>Неструктурность On Error заключается в том, что я не знаю, что следует написать вместо On Error Goto 0 для восстановления предыдущего обработчика. Надо смотреть код выше. А если там есть что-то типа
al>
al>if .... Then
al> On error Goto туда
al>else
al> On error goto сюда
al>end if
al>
ИМХО оператор, который скорее вреден, чем полезен — это
On Error Goto 0
Если вы пишете такой код, что вам ручками приходится восстанавливать измененные обработчики, то вам явно стоит задуматься о рефакторинге.
У меня есть предположение, что вы также пишете функции и процедуры на много десятков строк, поэтому на каждый десяток строк вам приходится менять и заново восстанавливать обработчик ошибок.
Если же вы все же решите начинать СТРУКТУРИРОВАТЬ свой код не с обработки ошибок, а с четкости изложения мыслей и формализации операций — то есть будете выделять каждый блок операторов, выполняющий определенное законченное действие в отдельную функцию/процедуру/метод, то:
Ваши функции и процедуры начнут занимать максимум пару десятков строк, а следовательно необходимость ручками восстанавливать обработчики ошибок отпадет сама собой: они будут автоматически восстанавливаться при выходе из функций/процедур/методов.
Но главное — вы получите действительно структурированный легко читаемый код.
И никаких
Не всегда программу удается свести к нескольким процедурам из 3-10 строчек. Некоторые сложные алгоритмы требуют больших процедур.
Но не обязвтельно такие ситуации возникают в очень больших процедурах. Предположим, что в начале процедура рбращается к колекции за каким-то элементом, после этого вызывает некий метод этого элемента. При этом возможно, что этого элемента нет в коллекции (это одна ошибка), этот элемент есть, но имеет значение Noithing и кроме того вызываемый метод может вызвать ошибку.
sub XXX(name as String)
dim o as Object
set o=g_Coll.Item(name)
o.DoSomething
end sub
Что здесь подвергать рефакторингу?
Используя On Error goto я должен написать
sub XXX(name as String)
on error goto ErrHandler
dim o as Object
set o=g_Coll.Item(name)
o.DoSomething
exit sub
ErrHandler:
' обработка ошибки
exit sub
end sub
В этом случае мне абсолютно не нравится ситуация, когда в одном месте я должен разбираться с тем, что же конкретно вызвало ошибку, т.к. мне, например может быть нужно выдать некоторое диагностическое сообщение. Из Err.Code далеко не всегда можно понять, что именно произошло и в каком месте. Например, если у o вызывается несколько методов, то из Err.Code уже невозможно понять, гда именно произошла ошибка.
Поэтому я напишу:
sub XXX(name as String)
on error resume next
err.Clear
dim o as Object
set o=g_Coll.Item(name)
if o is Nothing then
' моя обработка этой ситуации
exit sub
end if
o.DoSomething
if err<>0 then
' моя обработка этой ситуации
err.clear
exit sub
end if
on error goto 0 ' согласен, что это не нужно, но для меня это нечто типа операторных скобок - признак того, что где - то в начале вызван On error resume next
end sub
Здравствуйте, al, Вы писали:
al>Не всегда программу удается свести к нескольким процедурам из 3-10 строчек. Некоторые сложные алгоритмы требуют больших процедур.
В таких алгоритмах обычно достаточно проверить корректность входных данных, а затем не проверять ошибок, поэтому хватает одного обработчика ошибок.
al>Но не обязвтельно такие ситуации возникают в очень больших процедурах. Предположим, что в начале процедура рбращается к колекции за каким-то элементом, после этого вызывает некий метод этого элемента. При этом возможно, что этого элемента нет в коллекции (это одна ошибка), этот элемент есть, но имеет значение Noithing и кроме того вызываемый метод может вызвать ошибку.
В таком случае стоит выделить работу с конкретным элементом в отдельную функцию/процедуру/метод, при этом проверять значение элемента на равенство Nothing до вызова метода.
al>
al>sub XXX(name as String)
al> on error goto ErrHandler
al> dim o as Object
al> set o=g_Coll.Item(name)
al> o.DoSomething
al> exit sub
al>ErrHandler:
al> ' обработка ошибки
al> exit sub
al>end sub
al>
Sub SafeDoSomething(o As Object)
On Error Goto ObjectHandler
o.DoSomething
Exit Sub
ObjectHandler:
MsgBox"ObjectHandler"End Sub
Sub XXX(name As String)
On Err Goto CollectionHandler
dim o as Object
set o=g_Coll.Item(name)
SafeDoSomething o
Exit Sub
CollectionHandler:
MsgBox"CollectionHandler"End Sub
Сие ИМХО более структурировано и четко выражает суть того, что выполняется в программе.
al>В этом случае мне абсолютно не нравится ситуация, когда в одном месте я должен разбираться с тем, что же конкретно вызвало ошибку, т.к. мне, например может быть нужно выдать некоторое диагностическое сообщение. Из Err.Code далеко не всегда можно понять, что именно произошло и в каком месте. Например, если у o вызывается несколько методов, то из Err.Code уже невозможно понять, гда именно произошла ошибка.
С поиском источника ошибки в целом согласен, но все же (в теории, конечно), такую процедуру лучше разбить на несколько.
И такие DoSafeSometing писать для каждого метода? А если методов штук 200 и у некоторых по пять/десять параметров? Пиать кучу оберток и таскать кучу параметров через стек?
А в Вашем коде совершенно не отображено то, что я хочу знать об ошибке вызова DoSomthing в том есте, где я ее вызываю. т.е. SafeDoSomthing должна быть функцией, возвращающей, например, False в случае ошибки. А если DoSomthing — само функция, и мне нужен ее результат. Тогда что, заводить еще один ByRef параметр у SafeDoSomthing? Оч. хороший рефактроинг. Но я лучше буду использовать On Erorr Resume Next.