- Исключения
- Обработка исключений
- Обработка исключительных ситуаций
- Исключения и обработка исключений
- Общие сведения об исключениях
- Спецификация языка C#
- Обработка и создание исключений в .NET
- Исключения
- Исключения и традиционные методы обработки ошибок
- Часто встречающиеся исключения
- Лучшие методики обработки исключений
- Использование блоков try/catch/finally для восстановления после ошибок или высвобождения ресурсов
- Обработка общих условий без выдачи исключений
- Устранение исключений при разработке классов
- Выдача исключений вместо возврата кода ошибки
- Использование предопределенных типов исключений .NET
- Завершайте имена классов исключений словом Exception
- Включение трех конструкторов в пользовательские классы исключений
- Обеспечение доступности данных об исключении при удаленном выполнении кода
- Использование грамматически правильных сообщений об ошибке
- Включение локализованной строки сообщения в каждое исключение
- Предоставление дополнительных свойств в пользовательских исключениях по мере необходимости
- Размещение операторов throw для удобной трассировки стека
- Использование методов построителя исключений
- Восстановление состояния, если методы не выполняются из-за исключения
Исключения
Обработка исключений
В процессе работы программы могут возникать различные ошибки. Например, при передаче файла по сети оборвется сетевое подключение или будут введены некорректные и недопустимые данные, которые вызовут падение программы. Такие ошибки еще называются исключениями. Если исключение не обработано, то при его возникновении программа прекращает свою работу.
Например, в следующей программе происходит деление чисел:
Эта программа успешно скомпилируется, но при ее выполнении возникнет ошибка, поскольку в коде производится деление на ноль, после чего программа аварийно завершится.
С одной стороны, мы можем в функции divide определить проверку и выполнять деление, если параметр b не равен 0. Однако нам в любом случае надо возвращать из функции divide некоторый результат — некоторое число. То есть мы не можем просто написать:
И в этом случае нам надо известить систему о возникшей ошибке. Для этого используется оператор throw .
Оператор throw генерирует исключение. Через оператор throw можно передать информацию об ошибке. Например, функция divide могла бы выглядеть следующим образом:
То есть если параметр b равен 0, то генерируем исключение.
Но это исключение еще надо обработать в коде, где будет вызываться функция divide. Для обработки исключений применяется конструкция try. catch . Она имеет следующую форму:
В блок после ключевого слова try помещается код, который потенциально может сгенерировать исключение.
После ключевого слова catch в скобках идет параметр, который передает информацию об исключении. Затем в блоке производится собственно обработка исключения.
Так изменим весь код следующим образом:
Код, который потенциально может сгенерировать исключение — вызов функции divide помещается в блок try.
В блоке catch идет обработка исключения. Причем многоточие в скобках после оператора catch ( catch(. ) ) позволяет обработать любое исключение.
В итоге когда выполнение программы дойдет до строки double z = divide(x, y); , будет сгенерировано исключение, поэтому последующие инструкции из блока try выполняться не будут, а управление перейдет в блок catch, в котором на консоль просто выводится сообщение об ошибке. После выполнения блока catch программа аварийно не завершится, а продолжит свою работу, выполняя операторы после бллока catch:
Чтобы скомпилировать данный пример с конструкцией try. catch с помощью g++ может потребоваться использование флага -static :
Однако в данном случае мы только знаем, что произошла какая-то ошибка, а какая именно, неизвестно. Поэтому в выражении catch мы можем получить то сообщение, которое передается оператору throw:
С помощью параметра const char* msg получаем сообщение, которое предано оператору throw, и выводит это сообщение на консоль. И в этом случае консольный вывод будет выглядеть следующим образом:
Таким образом, мы можем узнать суть возникшего исключения.
Источник
Обработка исключительных ситуаций
Исключение — это событие при выполнении программы, которое приводит к её ненормальному или неправильному поведению.
Существует два вида исключений:
- Аппаратные (структурные, SE-Structured Exception), которые генерируются процессором. К ним относятся, например,
- деление на 0;
- выход за границы массива;
- обращение к невыделенной памяти;
- переполнение разрядной сетки.
- Программные , генерируемые операционной системой и прикладными программами – возникают тогда, когда программа их явно инициирует. Когда встречается аномальная ситуация, та часть программы, которая ее обнаружила, может сгенерировать, или возбудить , исключение.
Механизм структурной обработки исключений позволяет однотипно обрабатывать как программные, так и аппаратные исключения.
Обработка программных исключений
Фундаментальная идея обработки исключительных ситуаций состоит в том, что функция, обнаружившая проблему, но не знающая как её решить, генерирует исключение в надежде, что вызвавшая её (непосредственно или косвенно) функция сможет решить возникшую проблему. Функция, которая может решать проблемы данного типа, указывает, что она перехватывает такие исключения.
Для реализации обработки исключений в C++ используйте выражения try , throw и catch .
Блок try <…>позволяет включить один или несколько операторов, которые могут создавать исключение.
Выражение throw используется только в программных исключениях и означает, что исключительное условие произошло в блоке try . В качестве операнда выражения throw можно использовать объект любого типа. Обычно этот объект используется для передачи информации об ошибке.
Для обработки исключений, которые могут быть созданы, необходимо реализовать один или несколько блоков catch сразу после блока try . Каждый блок catch указывает тип исключения, которое он может обрабатывать.
Сразу за блоком try находится защищенный раздел кода . Выражение throw вызывает исключение, т.е. создает его.
Блок кода после catch является обработчиком исключения . Он перехватывает исключение, вызываемое, если типы в выражениях throw и catch совместимы. Если оператор catch задает многоточие (…) вместо типа, блок catch обрабатывает все типы исключений.
Поскольку блоки catch обрабатываются в порядке программы для поиска подходящего типа, обработчик с многоточием должен быть последним обработчиком для соответствующего блока try . Как правило, блок catch (…) используется для ведения журнала ошибок и выполнения специальной очистки перед остановкой выполнения программы.
Ниже приведен пример обработки программного исключения. В реальных программах посылка исключения командой throw , как правило, является следствием проверки какого-либо условия.
Источник
Исключения и обработка исключений
Функции обработки исключений в языке C# помогают вам справиться с непредвиденными или исключительными проблемами, которые возникают при выполнении программы. При обработке исключений используются ключевые слова try , catch и finally для действий, которые могут оказаться неудачными. Это позволяет обрабатывать ошибки так, как кажется разумным, а также правильно высвобождать ресурсы. Исключения могут создаваться средой выполнения (CLR), платформой .NET , библиотеками сторонних поставщиков или кодом самого приложения. Чтобы создать исключение, используйте ключевое слово throw .
Во многих случаях исключение может создаваться не тем методом, который вызывается в вашем коде, а одним из последующих методов в стеке вызовов. Если создается такое исключение, среда CLR разворачивает стек, находит метод с блоком catch для исключений соответствующего типа и выполняет первый такой обнаруженный блок catch . Если подходящий блок catch не будет обнаружен во всем стеке вызовов, среда CLR завершает процесс и выводит сообщение для пользователя.
В этом примере метод выполняет проверку деления на нуль и перехватывает ошибку. Если не использовать обработку исключений, такая программа завершит работу с ошибкой DivideByZeroException was unhandled (Исключение DivideByZero не обработано).
Общие сведения об исключениях
Исключения имеют следующие свойства.
- Исключения представляют собой типы, производные в конечном счете от System.Exception .
- Используйте блок try для выполнения таких инструкций, которые могут создавать исключения.
- Когда внутри такого блока try возникает исключение, поток управления переходит к первому подходящему обработчику исключений в стеке вызовов. В C# ключевое слово catch обозначает обработчик исключений.
- Если для созданного исключения не существует обработчиков, выполнение программы прекращается с сообщением об ошибке.
- Не перехватывайте исключение, если вы не намерены его обрабатывать с сохранением известного состояния приложения. Если вы перехватываете System.Exception , создайте его заново в конце блока catch , используя ключевое слово throw .
- Если блок catch определяет переменную исключения, ее можно использовать для получения дополнительных сведений о типе созданного исключения.
- Программа может явным образом создавать исключения с помощью ключевого слова throw .
- Объекты исключения содержат подробные сведения об ошибке, например состояние стека вызовов и текстовое описание ошибки.
- Код в блоке finally выполняется, даже если создано исключение. Используйте блок finally , чтобы высвободить ресурсы, например закрыть потоки и файлы, которые были открыты внутри блока try .
- Управляемые исключения реализованы в платформе .NET на основе структурированного механизма обработки исключений Win32. Дополнительные сведения см. в статьях Structured Exception Handling (C/C++) (Структурированная обработка исключений в C и C++) и A Crash Course on the Depths of Win32 Structured Exception Handling (Интенсивное погружение в структурированную обработку исключений на платформе Win32).
Спецификация языка C#
Дополнительные сведения см. в разделе Исключения в Спецификации языка C#. Спецификация языка является предписывающим источником информации о синтаксисе и использовании языка C#.
Источник
Обработка и создание исключений в .NET
Необходимо реализовать возможность единообразной обработки приложениями ошибок, происходящих во время выполнения. Среда .NET предоставляет модель для единообразного уведомления приложений об ошибках: операции .NET информируют о сбое посредством выдачи исключений.
Исключения
Исключение — это любое состояние ошибки или непредвиденное поведение, возникающее при выполнении программы. Исключения могут возникать из-за сбоя в вашем или вызываемом коде (например, в общей библиотеке), недоступности ресурсов ОС, неожиданных состояний, возникающих в среде выполнения (например, код, который невозможно проверить) и по другим причинам. После некоторых из этих состояний приложение может восстановиться, после других — нет. В большинстве случаев вы можете выполнить восстановление после большинства исключений в приложении, но не после исключений среды выполнения.
В .NET исключение — это объект, наследуемый от класса System.Exception. Исключение создается из области кода, где произошла проблема. Исключение передается вверх по стеку до тех пор, пока его не обработает приложение либо программа не завершится.
Исключения и традиционные методы обработки ошибок
Традиционно модели обработки ошибок разных языков программирования основываются либо на уникальном для языка способе обнаружения ошибок и отыскании для них обработчиков, либо на механизме обработки ошибок, предоставляемом операционной системой. Способ обработки исключений, реализуемый в .NET, обладает следующими преимуществами:
Создание и обработка исключений работают одинаково для языков программирования .NET.
Не требует определенного синтаксиса языка для обработки исключений, а позволяет каждому языку определить собственный синтаксис.
Исключения можно создавать между разными процессами и даже компьютерами.
В приложение можно добавить код обработки исключений для повышения надежности программы.
Исключения обеспечивают ряд преимуществ по сравнению с другими методами уведомления об ошибках, например кодами возврата. Сбои не остаются незамеченными, так как среда выполнения завершает работу приложения при наличии необработанного исключения. Недопустимые значения не распространяются по системе из-за того, что код не способен выполнить проверку кода возврата ошибки.
Часто встречающиеся исключения
В следующей таблице перечислены некоторые общие исключения с примерами возможных причин.
Источник
Лучшие методики обработки исключений
Хорошо спроектированное приложение обрабатывает исключения и ошибки, чтобы предотвратить сбои приложения. В этом разделе описываются рекомендации по обработке и созданию исключений.
Использование блоков try/catch/finally для восстановления после ошибок или высвобождения ресурсов
Используйте блоки try / catch , выделив с их помощью код, который потенциально может явиться источником исключения, таким образом можно будет выполнить восстановление кода после возникновения этого исключения. В блоках catch следует всегда упорядочивать исключения от более производных к менее производным. Все исключения, производные от Exception. Более производные исключения не обрабатываются предложением catch, которому предшествует предложение catch для базового класса исключения. Если ваш код не удается восстановить после возникновения исключения, не перехватывайте это исключение. Включите методы выше по стеку вызовов для восстановления по мере возможности.
Очистите ресурсы, выделенные с помощью инструкций using или блоков finally . Рекомендуется использовать инструкции using для автоматической очистки ресурсов при возникновении исключений. Используйте блоки finally , чтобы очистить ресурсы, которые не реализуют IDisposable. Код в предложении finally выполняется почти всегда — даже при возникновении исключений.
Обработка общих условий без выдачи исключений
Для условий, которые могут возникнуть, но способны вызвать исключение, рекомендуется реализовать обработку таким способом, который позволит избежать исключения. Например, при попытке закрыть уже закрытое подключение возникает InvalidOperationException . Этого можно избежать, используя оператор if для проверки состояния подключения перед попыткой закрыть его.
Если состояние подключения перед закрытием не проверяется, исключение InvalidOperationException можно перехватить.
Выбор конкретного способа зависит от того, насколько часто ожидается возникновение данного события.
Используйте обработку исключений, если событие не происходит очень часто, то есть если событие носит действительно исключительный характер и указывает на ошибку (например, в случае неожиданного конца файла). При использовании обработки исключений в обычных условиях выполняется меньше кода.
Если событие происходит регулярно в рамках нормальной работы программы, выполняйте проверку на наличие ошибок прямо в коде. Проверка на наличие распространенных условий ошибки позволяет выполнять меньший объем кода благодаря устранению исключений.
Устранение исключений при разработке классов
Класс может предоставлять методы и свойства, позволяющие избежать вызова, способного выдать исключение. Например, класс FileStream содержит методы, позволяющие определить, достигнут ли конец файла. Это позволяет избежать появления исключения, создаваемого в случае выполнения чтения после окончания файла. В следующем примере показан способ чтения до конца файла без выдачи исключения.
Другой способ устранения исключений заключается в том, что для наиболее общих и часто встречающихся ошибок следует возвращать значение NULL (или значение по умолчанию). Такие ошибки могут относиться к обычному потоку управления. Возвращая значение NULL (или значение по умолчанию) в таких случаях, можно уменьшить влияние на производительность приложения.
При выборе типа значения Nullable или значения по умолчанию в качестве индикатора ошибки учитывайте особенности приложения. При использовании Nullable «default принимает значение null , а не Guid.Empty . В некоторых случаях добавление Nullable помогает более точно определить, присутствует или отсутствует значение. Но в определенных ситуациях добавление Nullable может привести к созданию лишних необязательных случаев для проверки, что повышает вероятность ошибки.
Выдача исключений вместо возврата кода ошибки
Исключения гарантируют, что сбои не останутся незамеченными из-за того, что вызывающий код не проверил код возврата.
Использование предопределенных типов исключений .NET
Создавайте новый класс исключений, только если предопределенное исключение не подходит. Пример:
Вызывайте исключение InvalidOperationException, если значение свойства или вызов метода не соответствуют текущему состоянию объекта.
Порождайте исключение ArgumentException или одного из предварительно определенных классов, которые являются производными от ArgumentException, если передаются недопустимые параметры.
Завершайте имена классов исключений словом Exception
Если требуется пользовательское исключение, присвойте ему соответствующее имя и сделайте его производным от класса Exception. Пример:
Включение трех конструкторов в пользовательские классы исключений
При создании собственных классов исключений можно использовать по меньшей мере три общих конструктора: конструктор без параметров, конструктор, принимающий строковое сообщение, и конструктор, принимающий строковое сообщение и внутреннее исключение.
Exception(), использующий значения по умолчанию.
Exception(String), принимающий строковое сообщение.
Exception(String, Exception), принимающий строковое сообщение и внутреннее исключение.
Обеспечение доступности данных об исключении при удаленном выполнении кода
При создании пользовательских исключений следует обеспечить доступность метаданных исключений для удаленно исполняемого кода.
Например, для реализаций .NET, которые поддерживают домены приложений, могут возникать исключения для этих доменов. Предположим, что домен приложения А создает домен приложения В, который выполняет код, вызывающий исключение. Чтобы домен приложения A правильно перехватил и обработал исключение, он должен найти сборку, которая содержит исключение, порожденное доменом приложения B. Если домен приложения B порождает исключение, содержащееся в сборке в его базовой папке приложения, но не в базовой папке приложения домена A, то домен приложения A не сможет найти исключение и среда CLR породит исключение FileNotFoundException. Чтобы избежать такой ситуации, можно развернуть сборку, содержащую сведения об исключении, двумя способами:
Поместите эту сборку в общую базу приложения, совместно используемую обоими доменами приложений.
Если у этих доменов нет общей базы приложения, то подпишите сборку, содержащую сведения об исключении, строгим именем и разверните ее в глобальном кэше сборок.
Использование грамматически правильных сообщений об ошибке
Составляйте понятные предложения, указывая в конце знаки препинания. Каждое предложение в строке, назначенной свойству Exception.Message, должно заканчиваться точкой. Например, «Таблица журнала переполнена.» будет подходящей строкой сообщения.
Включение локализованной строки сообщения в каждое исключение
Сообщение об ошибке, показываемое пользователю, извлекается из свойства Exception.Message созданного исключения, а не из имени класса исключения. Как правило, вы присваиваете значение свойству Exception.Message, передав строку сообщения аргументу message конструктора исключений.
Для локализованных приложений необходимо предоставить строку локализованного сообщения для всех исключений, которые может создавать приложение. Используйте файлы ресурсов для предоставления локализованных сообщений об ошибках. Сведения о локализации приложений и извлечении локализованных строк см. в следующих статьях:
Предоставление дополнительных свойств в пользовательских исключениях по мере необходимости
Дополнительные сведения (кроме строки настраиваемого сообщения) включайте в исключение только в случаях, когда в соответствии со сценарием программирования такие дополнительные сведения могут оказаться полезными. Например, исключение FileNotFoundException предоставляет свойство FileName.
Размещение операторов throw для удобной трассировки стека
Трассировка стека начинается в операторе, породившем исключение, и завершается оператором catch , перехватывающим это исключение.
Использование методов построителя исключений
Обычно класс генерирует одно и то же исключение из различных мест своей реализации. Чтобы избежать повторения кода, используйте вспомогательные методы, создающие исключение и затем возвращающие его. Пример:
В некоторых случаях для создания исключения лучше воспользоваться конструктором исключений. В качестве примера можно привести класс глобальных исключений, например ArgumentException.
Восстановление состояния, если методы не выполняются из-за исключения
Вызывающие объекты должны предполагать, что при создании исключения из метода не возникают побочные эффекты. Например, если у вас есть код, который передает деньги, списывая их с одного счета и внося на другой, и при начислении средств возникает исключение, списание средств применяться не должно.
Описанный выше метод непосредственно не создает исключения, однако при его написании необходимо соблюдать осторожность, чтобы при сбое операции начисления списание отменялось.
Один из способов обработки в этой ситуации заключается в перехвате всех исключений, выданных транзакцией начисления средств, и откате транзакции списания средств.
В этом примере показано использование throw для повторного порождения исходного исключения. Это позволяет вызывающим объектам проще установить фактическую причину проблемы, не обращаясь к свойству InnerException. Альтернативным способом является выдача нового исключения с включением исходного исключения в качестве внутреннего:
Источник