Очевидно, что обработка ошибок в целом является большой темой, и наилучшая практика во многом зависит от возможностей языка, с которым вы работаете, и от того, как подпрограмма, которую вы кодируете, вписывается в другие подпрограммы. Поэтому я ограничу свой ответ VBA (используется в Excel) и процедурами библиотечного типа того типа, который вы описываете.
Исключения и коды ошибок в подпрограммах библиотеки
В этом случае я бы не использовал бы код возврата. VBA поддерживает форму обработки исключений, которая, хотя и не такая мощная, как более стандартная форма в C ++ / Java / ??. NET, довольно похожа. Так что совет от этих языков в целом применим. Вы используете исключения, чтобы сообщить вызывающим подпрограммам, что вызываемая подпрограмма не может выполнять свою работу по какой-либо причине. Вы обрабатываете исключения на самом низком уровне, где вы можете сделать что-то значимое в этом сбое.
Бьярн Страуструп дает очень хорошее объяснение того, почему исключения лучше, чем коды ошибок для такой ситуации в этой книге. (Книга посвящена C ++, но принципы обработки исключений C ++ и обработки ошибок VBA одинаковы.)
http://www2.research.att.com/~bs/3rd.html
Вот хорошая выдержка из Раздела 8.3:
Когда программа состоит из отдельных
модули, и особенно когда те
модули поставляются отдельно разработанными
библиотеки, обработка ошибок должна быть
разделены на две отдельные части: [1]
Сообщение об ошибках, которые
не может быть решена локально [2]
обработка ошибок, обнаруженных в других местах
Автор библиотеки может обнаружить
ошибки во время выполнения, но не в целом
есть идеи, что с ними делать.
Пользователь библиотеки может знать, как
справиться с такими ошибками, но не может
обнаружить их - иначе они будут
обрабатываются в коде пользователя, а не
ушел в библиотеку, чтобы найти.
В разделах 14.1 и 14.9 также рассматриваются исключения и коды ошибок в контексте библиотеки. (Копия книги онлайн на сайте archive.org.)
Вероятно, об этом много говорится о stackoverflow. Я только что нашел это, например:
Исключение против кода ошибки и подтверждения
(Могут быть подводные камни, связанные с правильным управлением ресурсами, которые должны быть очищены при использовании исключений, но они на самом деле здесь не применяются.)
Исключения в VBA
Вот как выглядит возникновение исключения в VBA (хотя терминология VBA «вызывает ошибку»):
Function AddArrays(arr1, arr2)
Dim i As Long
Dim result As Variant
' Some error finding code here, e.g.
' - Are input arrays of same size?
' - Are input arrays numeric? (can't add strings, objects...)
' - Etc.
'Assume errorsFound is a variable you populated above...
If errorsFound Then
Call Err.Raise(SOME_BAD_INPUT_CONSTANT) 'See help about the VBA Err object. (SOME_BAD_INPUT_CONSTANT is something you would have defined.)
End If
' If no errors found, do the actual work...
ReDim result(LBound(arr1) To UBound(arr1))
For i = LBound(arr1) To UBound(arr1)
result(i) = arr1(i) + arr2(i)
Next i
AddArrays = result
End Function
Если эта подпрограмма не улавливает ошибку, VBA предоставит другим подпрограммам над ней в стеке вызовов шанс (см .: Ошибка VBA "Bubble Up" ). Вот как звонящий может сделать это:
Public Function addExcelArrays(a1, a2)
On Error Goto EH
addExcelArrays = AddArrays(a1, a2)
Exit Function
EH:
'ERR_VBA_TYPE_MISMATCH isn't defined by VBA, but it's value is 13...
If Err.Number = SOME_BAD_INPUT_CONSTANT Or Err.Number = ERR_VBA_TYPE_MISMATCH Then
'We expected this might happen every so often...
addExcelArrays = CVErr(xlErrValue)
Else
'We don't know what happened...
Call debugAlertUnexpectedError() 'This is something you would have defined
End If
End Function
Что означает «сделать что-то значимое», зависит от контекста вашего приложения. В приведенном выше примере с вызывающим абонентом it решает, что некоторые ошибки следует обработать, возвращая значение ошибки, которое Excel может поместить в ячейку листа, в то время как другим требуется неприятное предупреждение. (Здесь ситуация с VBA в Excel на самом деле не является плохим конкретным примером, потому что многие приложения делают различие между внутренней и внешней подпрограммами, а также между исключениями, которые, как вы ожидаете, сможете обработать, и условиями ошибок, о которых вы просто хотите знать но на что у вас нет ответа.)
Не забывайте утверждения
Поскольку вы упомянули отладку, также стоит отметить роль утверждений. Если вы ожидаете, что AddArrays когда-либо будут вызываться только подпрограммами, которые фактически создали свои собственные массивы или иным образом подтвердили, что они используют массивы, вы можете сделать это:
Function AddArrays(arr1, arr2)
Dim i As Long
Dim result As Variant
Debug.Assert IsArray(arr1)
Debug.Assert IsArray(arr2)
'rest of code...
End Function
Фантастическое обсуждение различий между утверждениями и исключениями здесь:
Отладка. Утверждение и исключение
Я привел пример здесь:
Утверждает ли это зло?
Некоторые советы VBA по поводу общих процедур обработки массивов
Наконец, как примечание для VBA, существуют варианты VBA, и массивы поставляются с рядом ловушек, которых следует избегать при попытке написать общие подпрограммы библиотеки.Массивы могут иметь более одного измерения, их элементы могут быть объектами или другими массивами, их начальный и конечный индексы могут быть чем угодно, и т. Д. Вот пример (непроверенный и не пытающийся быть исчерпывающим), который объясняет часть этого:
'NOTE: This has not been tested and isn't necessarily exhaustive! It's just
'an example!
Function addArrays(arr1, arr2)
'Note use of some other library functions you might have...
'* isVect(v) returns True only if v is an array of one and only one
' dimension
'* lengthOfArr(v) returns the size of an array in the first dimension
'* check(condition, errNum) raises an error with Err.Number = errNum if
' condition is False
'Assert stuff that you assume your caller (which is part of your
'application) has already done - i.e. you assume the caller created
'the inputs, or has already dealt with grossly-malformed inputs
Debug.Assert isVect(arr1)
Debug.Assert isVect(arr2)
Debug.Assert lengthOfArr(arr1) = lengthOfArr(arr2)
Debug.Assert lengthOfArr(arr1) > 0
'Account for VBA array index flexibility hell...
ReDim result(1 To lengthOfArr(arr1)) As Double
Dim indResult As Long
Dim ind1 As Long
ind1 = LBound(arr1)
Dim ind2 As Long
ind2 = LBound(arr2)
Dim v1
Dim v2
For indResult = 1 To lengthOfArr(arr1)
'Note implicit coercion of ranges to values. Note that VBA will raise
'an error if an object with no default property is assigned to a
'variant.
v1 = arr1(ind1)
v2 = arr2(ind2)
'Raise errors if we have any non-numbers. (Don't count a string
'with numeric text as a number).
Call check(IsNumeric(v1) And VarType(v1) <> vbString, xlErrValue)
Call check(IsNumeric(v2) And VarType(v2) <> vbString, xlErrValue)
'Now we don't expect this to raise errors.
result(indResult) = v1 + v2
ind1 = ind1 + 1
ind2 = ind2 + 1
Next indResult
addArrays = result
End Function