Как создать свое исключение c

Как создать свое исключение c

Если нас не устраивают встроенные типы исключений, то мы можем создать свои типы. Базовым классом для всех исключений является класс Exception, соответственно для создания своих типов мы можем унаследовать данный класс.

Допустим, у нас в программе будет ограничение по возрасту:

В классе Person при установке возраста происходит проверка, и если возраст меньше 18, то выбрасывается исключение. Класс Exception принимает в конструкторе в качестве параметра строку, которое затем передается в его свойство Message.

Но иногда удобнее использовать свои классы исключений. Например, в какой-то ситуации мы хотим обработать определенным образом только те исключения, которые относятся к классу Person. Для этих целей мы можем сделать специальный класс PersonException:

По сути класс кроме пустого конструктора ничего не имеет, и то в конструкторе мы просто обращаемся к конструктору базового класса Exception, передавая в него строку message. Но теперь мы можем изменить класс Person, чтобы он выбрасывал исключение именно этого типа и соответственно в основной программе обрабатывать это исключение:

Однако необязательно наследовать свой класс исключений именно от типа Exception, можно взять какой-нибудь другой производный тип. Например, в данном случае мы можем взять тип ArgumentException, который представляет исключение, генерируемое в результате передачи аргументу метода некорректного значения:

Каждый тип исключений может определять какие-то свои свойства. Например, в данном случае мы можем определить в классе свойство для хранения устанавливаемого значения:

В конструкторе класса мы устанавливаем это свойство и при обработке исключения мы его можем получить:

Создание собственных классов исключений в C#

При разработке программного обеспечения в C# и не только, довольно часто встроенных типов исключений бывает не достаточно. Например, при взаимодействии с каким-либо API web-сервиса вам может понадобиться не только предоставить пользователю сообщение об ошибке, но и передать её код, в соответствии с документацией по API сервиса, какую-то служебную информацию и так далее. И здесь нам уже вряд ли хватить стандартных возможностей того же класса Exception — потребуется создать собственный класс исключений, который будет «заточен» на работу, например, с конкретными API. О том, как создавать собственные классы исключений мы сегодня и поговорим.

Пример создания собственного класса исключений

Как было сказано вые, стандартных классов исключений в C# может не всегда хватать. Например, мы хотим ограничить возраст пользователя и сделать так, чтобы зарегистрироваться могли только люди старше 18 лет. Используя класс Exception, мы можем написать следующий класс:

Здесь мы при задании значения свойству Age в классе Person проводим проверку и, если возраст менее 18 лет, то генерируем исключение с использованием класса Exception . Класс Exception в конструкторе принимает строку-сообщение. В основной программе происходит перехват и обработка исключения.

Технически, в представленном коде нет ошибок и цель достигнута — как только возраст оказывается менее 18 лет, то сразу генерируется исключение. Однако, в таких случаях удобнее использовать собственный класс исключений. Ответ на вопрос «Почему?» окажется на поверхности, если попытаться ответить на такой вопрос: что будет с кодом нашей программы, если мы захотим ограничить возраст не 18-ю годами, а, скажем, 40? Как минимум, нам придётся менять сообщение об ошибке. А что, если исключение будет генерироватьс не в одном, а в 100 местах в программе? Собственный класс исключений позволяет нам в этом случае:

  1. сделать код программы более универсальным и повысить его поддержку;
  2. сделать код программы более удобным для других разработчиков, так как, согласитесь, что тип исключений, например, AgeException говорит нам об ошибке больше, чем просто Exception .

Таким образом, собственный класс исключений можно создать таким:

По сути, этот класс сейчас ничем, кроме названия не отличается от базового Exception . Однако теперь мы можем создать собственные свойства у этого класса, или переопределять уже унаследованнные. Например,

В свойстве Value мы можем хранить, например, значение возраста и, при необходимости, его получать.

Базовым классом для собственных классов исключений может выступать любой класс исключений, например, мы можем унаследовать наш класс от одного из рассмотренных ранее классов:

и получить возможность переопределять уже доступные виртуальные свойства и методы класса ArgumentOutOfRangeException . Соответственно, теперь мы можем сделать наш класс Person более наглядным, например, таким:

В этом примере мы уже генерируем собственное исключение типа AgeException в конструктор которого передаем два числа — возраст, который мы пробовали указать в классе Person и минимально допустимый возраст, то есть 18 лет. Исходя из полученных значений мы создаем строку сообщения, которую и передаем в конструктор базового класса.

Итого

Создание собственных классов исключений в C# позволяет, с одной стороны, сделать код программы более читабельным и понятным, а, с другой стороны, используя все возможности наследования, повысить информативность генерируемых исключений. Классы исключений могут наследоваться не только от базового класса Exception , но и, в принципе, от любых известных классов исключений и переопределять их виртуальные методы и свойства.

Урок 33. Создание исключений в C#

Тридцать третий урок учебника по основам C# завершает исследование обработки исключений. В этой статье мы рассмотрим создание (выбрасывание) исключений для сообщения об ошибках. Это включает использование стандартных и пользовательских типов исключений.

Зачем создавать исключения?

В предыдущей части учебника по основам C# я представил обработку исключений и средство для перехвата исключений с помощью блока try / catch / finally в C#. В более старых языках вы можете выйти из подпрограммы рано и предоставить код возврата для указания состояния. Это возможно с помощью C#, но не использует возможности обработки исключений, предоставляемые языком. Предпочтительно явно вызывать или выбрасывать исключения при возникновении условий ошибки и разрешать захват исключений блоком try / catch / finally или системой выполнения C#.

Исключения следует создавать только при возникновении непредвиденного или недопустимого действия, которое не позволяет методу выполнить свою обычную функцию; обработка исключений не должна использоваться для нормального потока программы вместо условной обработки. Может быть трудно поддерживать код, который неправильно использует обработку исключений.

Хорошая практика создания исключений включает в себя:

  • создание исключения при передаче недопустимого значения параметра в метод. В этом случае необходимо создать исключение ArgumentException или один из его производных классов исключений.
  • создание исключения при вызове метода, который не может работать, потому что другие шаги должны быть предприняты заранее. В этом случае может быть вызвано исключение InvalidOperationException.

Чтобы вызвать исключение, вы используете команду throw. Синтаксис выглядит следующим образом:

Исключение — это объект исключения, содержащий сведения о возникшей ошибке. Он может быть объявлено как объект и инициализирован перед командой throw или включен в инструкцию throw, используя ключевое слово new и один из конструкторов исключения для задания свойств объекта.

В следующем примере используется консольное приложение, для работы которого требуется хотя бы один параметр запуска. Если параметр запуска не указан, создается исключение ArgumentException. Конструктор имеет один строковый параметр, содержащий сообщение об ошибке.

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

Примечание: класс объекта исключения, который нужно бросить, должен соответствовать условию ошибки. Каждый объект исключения имеет конструкторы, которые могут отличаться от показанных выше. Дополнительные сведения о других стандартных классах исключений смотри на сайте MSDN.

Повторное выбрасывание исключений

При перехвате исключения в блоке catch исключение считается обработанным, и выполнение кода продолжается в обычном режиме. Иногда вы захотите поймать исключение, но все равно его бросят, чтобы снова поймать. Например, можно перехватывать и регистрировать исключения, а затем повторно выбрасывать их для обработки вызывающей функцией.

Когда исключение создается явно с использованием предыдущего синтаксиса, создается новый объект исключения. Это содержит только основную информацию, которую вы указываете; информация, такая как трассировка стека исходного исключения, теряется. Чтобы повторно создать исходное исключение и сохранить все дополнительные сведения, используйте команду throw без указания объекта исключения:

В следующем примере показано, как используется этот синтаксис. Для простоты вызываемые методы не определены, поэтому этот код не может быть выполнен напрямую.

Свойство InnerException

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

В следующем примере расширяется пример re-throw выше путем создания FileNotFoundException с новым сообщением об ошибке и сведения о перехваченном исключении в свойстве InnerException.

Примечание: код выше приведен в качестве примера установки свойства InnerException. Это не очень хорошая практика, чтобы использовать catch-all и бросить новое исключение, так как это может замаскировать серьезные проблемы.

Пользовательские исключения

Платформа .NET Framework предоставляет богатый набор типов исключений, которые можно создавать и перехватывать. Однако список доступных исключений не охватывает все возможные варианты. Часто бывает целесообразно определить пользовательские исключения для конкретных сценариев. Это может быть достигнуто путем получения нового класса исключений из любого из существующих типов, обычно класса ApplicationException.

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

Определение пользовательского исключения

Наше пользовательское исключение будет сообщать об исключениях при печати страницы с полями, которые недопустимы для выбранного принтера. В соответствии с соглашениями об именах новый класс будет называться InvalidPrinterMarginsException. Чтобы определить новый класс в текущем пространстве имен и указать, что он является производным от ApplicationException, используйте следующий код:

Класс ApplicationException предоставляет три основных конструктора. Первый не требует параметров и создает исключение со значениями свойств по умолчанию. Второй принимает строковый параметр, содержащий сообщение об ошибке. Конечный конструктор позволяет указать сообщение и внутренний объект исключения. Эти три конструктора не наследуются автоматически новым типом исключения, поэтому их следует добавить следующим образом:

Созданиие перехват пользовательского исключения

Как только пользовательское исключение создано, оно может быть вызвано и поймано таким же образом, как и любое другое. Это включает в себя перехват точного исключения или нескольких типов, из которых оно получено. Действительно, одно пользовательское исключение может наследоваться от другого, чтобы создать глубокую иерархию исключений приложения для гибкой обработки ошибок.

В последнем примере пользовательское исключение сочетается с кодом консольного приложения. Эта программа создает пользовательское исключение в блоке try. Сообщение об исключении выводится следующим блоком catch.

Заключительное замечание по ApplicationException

Когда Microsoft создала платформу .NET framework, они определили два базовых класса. Это были системные исключения (SystemException) и пользовательские исключения (ApplicationException). При рассмотрении этой сегрегации Microsoft поняла, что преимущества такой структуры не были ожидаемыми. По этой причине Корпорация Майкрософт теперь рекомендует создавать пользовательские исключения непосредственно из класса Exception. Это делает иерархию исключений более плоской. Исключение ApplicationException остается частью платформы .NET framework для обеспечения обратной совместимости на момент написания статьи.


Автор этого материала — я — Пахолков Юрий. Я оказываю услуги по написанию программ на языках Java, C++, C# (а также консультирую по ним) и созданию сайтов. Работаю с сайтами на CMS OpenCart, WordPress, ModX и самописными. Кроме этого, работаю напрямую с JavaScript, PHP, CSS, HTML — то есть могу доработать ваш сайт или помочь с веб-программированием. Пишите сюда.

тегистатьи IT, уроки по си шарп, си шарп, исключения, ошибки

Как создать свое исключение c

Пользовательские классы-исключения

В предыдущей статье я рассказывал о генерации исключений в программах, написанных на C#. Прочитав её, Вы узнаете для чего предназначен данный механизм и как им пользоваться. А в этой статье я хочу рассказать о том, как создавать свои классы-исключения, т.е. такие классы, объекты которых, можно использовать для генерации исключений оператором throw.

И так, как мы помним, механизм генерации исключений нужен для информирования системы, о том, что в программе произошла некая исключительная ситуация (ошибка) и дальнейшее выполнение программы, без её обработки, невозможно! А объекты-исключения, который как бы «выбрасываются в эфир» оператором throw должны содержать информацию о произошедшей ошибке. И когда Вы разрабатываете свой специфический класс, Вам нужно позаботиться о генерации исключений в нештатных ситуациях, связанных с неправильным использованием этого класса. И вот тут начинается самое интересное…

Как мы помним, объект, который как бы «выбрасывается в эфир» оператором throw должен относиться к классу, который является прямым или косвенным наследником класса «Exception» (из пространства имен «System»), ну или вообще являться объектом этого класса. В примере из предыдущей статьи, мы поступали так:

Строка генерации исключения выделена. Так поступать можно, но не совсем правильно! Почему? Да потому, что при возможности, нужно максимально конкретизировать произошедшую ошибку (чтобы в месте её обработки было легче понять причину возникновения). Это делается как минимум двумя способами:

  • генерацией ошибки (объекта) определенного типа (класса), а не обобщенного, такого как «Exception», что использовался в примере выше;
  • передачей в создаваемый объект-исключение дополнительной информации.

Как это делается на практике? Ну в нашем примере, причиной ошибки служило некорректное значение аргумента, по-этому вместо объекта класса «Exception» мы могли бы использовать объект стандартного класса «ArgumentException» (думаю, название класса, говорит само за себя) из пространства имен «System«. Выглядеть это могло бы так:

Среди стандартных классов C#, есть ряд классов, которые предназначены для описания часто встречаемых в программах ошибок. Одним из таких классов является класс «ArgumentException».

Но в некоторых случаях, использовать уже имеющиеся классы для создания объектов при генерации исключений не получается, нет подходящих классов. В таком случае, программисту лучше написать собственный класс. Плюс ко всему, в собственном классе мы может создать дополнительные поля для хранения специфической информации. Например, кода ошибки. Вот пример такого класса:

Как не сложно заметить, в примере приведенном выше, мы создали класс наследник класса «Exception» и расширили его полем «errorCode», которое хранит код ошибки. Так же, добавили свойство, возвращающее этот код, и создали конструктор, который принимает описание ошибки и её код. Причем, в конструкторе, мы вызываем конструктор базового класса, которому передаем сообщение об ошибке. Сгенерить исключение такого типа в конструкторе класса «Person» мы могли бы так:

А обрабатывать так:

Как видите, в блоке catch мы явно указали что он обрабатывает исключения типа «PersonException» и исключения других типов в него не попадут. В следующей статье, я хочу подробнее коснуться этой темы.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *