Инициирование исключений
Выше уже говорилось о том, что метод ProcessFilе просто передает исключение в процедуру Sub Main, из которой он был вызван. В процедуре Sub Main команда вызова тоже заключена в блок Try-Catch, поэтому исключение будет обработано. С другой стороны, такое решение выглядит немного наивно, а если написанные вами классы будут использоваться другими программистами, оно становится попросту опасным. Но даже если дело как-нибудь обойдется, пользователи вашего кода вряд ли будут довольны тем, что вы без разбора передаете исключения, не пытаясь их обработать.
Лучше попытаться по возможности "прибрать" за собой, а затем воспользоваться ключевым словом Throw, чтобы передать объект исключения вызывающей стороне. В главе 4 упоминалось о том, что в VB.NET не поддерживается детерминированное завершение. Следовательно, если вы создали объект с методом Dispose, этот метод следует вызвать перед тем, как инициировать исключение. Сказанное относится и к открытию файлов, и к получению графического контекста. В следующем фрагменте представлена условная структура подобного кода:
Try ' Создание локального объекта с методом Dispose ' Код. который может инициировать исключения Catch(e As Exception) local Object.dispose() Throw e; End Try
Если вы не вызовете метод Dispose для своего локального объекта, то захваченные ресурсы так и не будут освобождены. Ведь ссылка на объект существует лишь в локальном коде; остальные части программы не обладают доступом к методу Dispose! С другой стороны, причина, по которой возникло исключение, остается в силе, поэтому о возникшей проблеме (например, о неудачной операции с файлом) нужно сообщить вызывающему коду. Для этого следует заново инициировать исключение командой Throw, как это сделано во второй выделенной строке.
Впрочем, если вы действительно хотите программировать "как положено", не ограничивайтесь простым перезапуском исключения. Постарайтесь сделать свой код как можно более информативным и включите в объект исключения дополнительную информацию. Для этого есть три возможности.
- Добавьте в исключение содержательное сообщение и инициируйте его заново. Возможно, новая информация окажется полезной.
- Инициируйте исключение одного из стандартных типов, производных от типа текущего исключения, чтобы оно лучше описывало ситуацию.
- Создайте новый класс исключения, производный от типа текущего исключения, который будет описывать ситуацию лучше, чем любой из стандартных классов.
Решения расположены по возрастанию приоритета, и в идеальном случае следует всегда использовать пункт 3. На практике программисты при выборе руководствуются своей оценкой того, какую информацию об исключении необходимо передать для дальнейшей обработки.
Для примера представьте такую ситуацию: из источника данных читаются пары "ключ/значение", и для последнего ключа не находится парного значения. Программа предполагает, что значение ассоциируется с каждым ключом, поэтому при попытке чтения возникает неожиданное исключение ввода-вывода (чтение данных из файла описано в главе 9).
Теперь вы хотите сообщить о происходящем вызывающей стороне. Чтобы добавить в исключение строку, можно воспользоваться специальной версией конструктора класса Exception:
Public Sub New(ByVal message As String)
В следующем фрагменте в объект IOException добавляется новая строка с сообщением об отсутствии значения для последнего ключа, после чего исключение инициируется заново.
Dim excep As New IQException("Missing value for last key") Throw excep