Читаем Интернет-журнал "Домашняя лаборатория", 2007 №9 полностью

Если в некотором модуле предполагается возможность появления исключений, то разумно предусмотреть и их обработку. В этом случае в модуле создается охраняемый try-блок, предваряемый ключевым словом try. Вслед за этим блоком следуют один или несколько блоков, обрабатывающих исключения, — catch-блоков. Каждый catch-блок имеет формальный параметр класса Exception или одного из его потомков. Если в try-блоке возникает исключение типа T, то catch-блоки начинают конкурировать в борьбе за перехват исключения. Первый по порядку catch-блок, тип формального аргумента которого согласован с типом T — совпадает с ним или является его потомком — захватывает исключение и начинает выполняться; поэтому порядок написания catch-блоков небезразличен. Вначале должны идти специализированные обработчики. Универсальным обработчиком является catch-блок с формальным параметром родового класса Exception, согласованным с исключением любого типа T. Универсальный обработчик, если он есть, стоит последним, поскольку захватывает исключение любого типа.

Конечно, плохо, когда в процессе работы той или иной процедуры возникает исключение. Однако его появление еще не означает, что процедура не сможет выполнить свой контракт. Исключение может быть нужным образом обработано, после чего продолжится нормальный ход вычислений приложения. Гораздо хуже, когда возникают ошибки в работе процедуры, не приводящие к исключениям. Тогда работа продолжается с неверными данными без исправления ситуации и даже без уведомления о возникновении ошибки. Наш пример показывает, что вычисления в C# могут быть небезопасными и следует применять специальные средства языка, такие как, например, checked-блоки, чтобы избежать появления подобных ситуаций.

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

Опасные вычисления в охраняемых проверяемых блоках

Такая ситуация возникает в первых двух try-блоках нашего примера. Эти блоки встроены в проверяемый checked-блок. В каждом из них используются опасные вычисления, приводящие к неверным результатам. Так, при присваивании невинного выражения b+1 из-за переполнения переменная b получает значение 0, а не 256. Поскольку вычисление находится в проверяемом блоке, то ошибка обнаруживается и результатом является вызов исключения. Далее, поскольку все это происходит в охраняемом блоке, то управление перехватывается и обрабатывается в соответствующем catch-блоке. Эту ситуацию следует отнести к нормальному, разумно построенному процессу вычислений.

Опасные вычисления в охраняемых непроверяемых блоках

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

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

Область действия проверки или ее отключения можно распространить и на отдельное выражение. В этом случае спецификаторы checked и unchecked предшествуют выражению, заключенному в круглые скобки. Такое выражение называется проверяемым (непроверяемым) выражением, a checked и unchecked рассматриваются как операции, допустимые в выражениях.

Опасные преобразования и методы класса Convert

Перейти на страницу:

Похожие книги