Перейти к содержимому

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

  • автор:

Как написать собственное исключение в отдельном классе и вызывать его при надобности?

Как написать собственное исключение в отдельном классе и вызывать его при надобности? Заранее спасибо! Можете ли описать что и куда вписывать? Я пока еще новичок и не особо понимаю. Вот само исключение, оно проверяет является ли вектор нулевым (v1 и v2 это векторы, а len1 и len2 их длины):

//exeption try < len1 = v1.Length(); len2 = v2.Length(); if (len1 == 0 || len2 == 0) < throw new Exception("Вектор не может быть нулевым"); >> catch (Exception e)

Отслеживать
задан 19 апр 2016 в 16:29
435 2 2 серебряных знака 14 14 бронзовых знаков
Если вам дан исчерпывающий ответ, отметьте его как верный (галка напротив выбранного ответа).
20 апр 2016 в 7:52

3 ответа 3

Сортировка: Сброс на вариант по умолчанию

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

Далее, чтобы ваше исключение соответствовало общепринятым стандартам, вам нужно иметь как минимум три конструктора: по умолчанию (без параметров), конструктор с сообщением, конструктор с сообщением и оригинальным исключением. Последний теоретически может быть опущен, но являетсмя обязательным, если вы «оборачиваете» какие-то системное исключением своим исключением.

(Для продвинутых: если исключение будет передаваться через границы, то обязательно нужно включить конструктор для сериализации. Подробнее в правиле FxCop’а.)

Кроме того, вы вольны включать в исключение любую дополнительную информацию, которая может помочь коду, обрабатывающему ваше исключение, принять нужное решение.

[Serializable] // опционально public class GoodException : Exception < public GoodException() < // . >public GoodException(string message) : base(message) < // . >public GoodException(string message, Exception innerException) : base (message, innerException) < // . >// опционально protected GoodException(SerializationInfo info, StreamingContext context) : base(info, context) < // логика сериализации >public string AdditionalInfo < get; set; >> 

Создание пользовательских исключений с локализованными сообщениями об исключениях

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

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

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

Предположим, что нужно создать StudentNotFoundException , содержащее свойство StudentName . Чтобы создать пользовательское исключение, сделайте следующее:

    Создайте сериализуемый класс, который наследует от Exception. Имя класса должно заканчиваться на Exception:

[Serializable] public class StudentNotFoundException : Exception
 Public Class StudentNotFoundException Inherits Exception End Class 
[Serializable] public class StudentNotFoundException : Exception < public StudentNotFoundException() < >public StudentNotFoundException(string message) : base(message) < >public StudentNotFoundException(string message, Exception inner) : base(message, inner) < >> 
 Public Class StudentNotFoundException Inherits Exception Public Sub New() End Sub Public Sub New(message As String) MyBase.New(message) End Sub Public Sub New(message As String, inner As Exception) MyBase.New(message, inner) End Sub End Class 
[Serializable] public class StudentNotFoundException : Exception < public string StudentName < get; >public StudentNotFoundException() < >public StudentNotFoundException(string message) : base(message) < >public StudentNotFoundException(string message, Exception inner) : base(message, inner) < >public StudentNotFoundException(string message, string studentName) : this(message) < StudentName = studentName; >> 
 Public Class StudentNotFoundException Inherits Exception Public ReadOnly Property StudentName As String Public Sub New() End Sub Public Sub New(message As String) MyBase.New(message) End Sub Public Sub New(message As String, inner As Exception) MyBase.New(message, inner) End Sub Public Sub New(message As String, studentName As String) Me.New(message) StudentName = studentName End Sub End Class 

Создание локализованных сообщений об исключениях

Вы создали пользовательское исключение и можете вызывать его где угодно с помощью кода, подобного следующему:

throw new StudentNotFoundException("The student cannot be found.", "John"); 
Throw New StudentNotFoundException("The student cannot be found.", "John") 

Проблема с предыдущей строкой заключается в том, что «The student cannot be found.» — это просто константная строка. В локализованном приложении вам необходимо иметь разные сообщения в зависимости от языка и региональных параметров пользователя. Вспомогательные сборки — хороший способ сделать это. Вспомогательная сборка — это библиотека DLL, содержащая ресурсы для определенного языка. При запросе конкретных ресурсов во время выполнения среда CLR находит этот ресурс в зависимости от языка и региональных параметров пользователя. Если вспомогательная сборка не найдена для этого языка и региональных параметров, используются ресурсы языка и региональных параметров по умолчанию.

Чтобы создать локализованные сообщения об исключениях:

  1. Создайте папку с именем Ресурсы для хранения файлов ресурсов.
  2. Добавьте в нее новый файл ресурсов. Для этого в Visual Studio щелкните правой кнопкой мыши папку в обозревателе решений и выберите Добавить>Новый элемент>Файл ресурсов. Присвойте файлу имя ExceptionMessages.resx. Это файл ресурсов по умолчанию.
  3. Добавьте пару «имя/значение» для сообщения об исключении, как показано на следующем рисунке: Добавление ресурсов в язык и региональные параметры по умолчанию
  4. Добавьте новый файл ресурсов для французского языка. Присвойте ему имя ExceptionMessages.fr-FR.resx.
  5. Снова добавьте пару «имя/значение» для сообщения об исключении, но со значением французского языка: Добавление ресурсов в язык и региональные параметры fr-FR
  6. После сборки проекта папка выходных данных сборки должна содержать папку fr-FR с файлом DLL, который является вспомогательной сборкой.
  7. Исключение вызывается с помощью кода, подобного приведенному ниже.

var resourceManager = new ResourceManager("FULLY_QUALIFIED_NAME_OF_RESOURCE_FILE", Assembly.GetExecutingAssembly()); throw new StudentNotFoundException(resourceManager.GetString("StudentNotFound"), "John"); 
Dim resourceManager As New ResourceManager("FULLY_QUALIFIED_NAME_OF_RESOURCE_FILE", Assembly.GetExecutingAssembly()) Throw New StudentNotFoundException(resourceManager.GetString("StudentNotFound"), "John") 

Примечание Если имя проекта — TestProject , а файл ресурсов ExceptionMessages.resx находится в папке Ресурсы проекта, полное имя файла ресурсов — TestProject.Resources.ExceptionMessages .

См. также

  • Как создать пользовательские исключения
  • Создание вспомогательных сборок
  • base (справочник по C#)
  • this (справочник по C#)

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

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

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

try < Person person = new Person < Name = "Tom", Age = 17 >; > catch (Exception ex) < Console.WriteLine($"Ошибка: "); > class Person < private int age; public string Name < get; set; >= ""; public int Age < get =>age; set < if (value < 18) throw new Exception("Лицам до 18 регистрация запрещена"); else age = value; >> >

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

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

class PersonException : Exception < public PersonException(string message) : base(message) < >>

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

try < Person person = new Person < Name = "Tom", Age = 17 >; > catch (PersonException ex) < Console.WriteLine($"Ошибка: "); > class Person < private int age; public string Name < get; set; >= ""; public int Age < get =>age; set < if (value < 18) throw new PersonException("Лицам до 18 регистрация запрещена"); else age = value; >> >

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

class PersonException : ArgumentException < public PersonException(string message) : base(message) < >>

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

class PersonException : ArgumentException < public int Value < get;>public PersonException(string message, int val) : base(message) < Value = val; >>

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

try < Person person = new Person < Name = "Tom", Age = 17 >; > catch (PersonException ex) < Console.WriteLine($"Ошибка: "); Console.WriteLine($"Некорректное значение: "); > class Person < private int age; public string Name < get; set; >= ""; public int Age < get =>age; set < if (value < 18) throw new PersonException("Лицам до 18 регистрация запрещена", value); else age = value; >> >

И в данном случае мы получим следующий консольный вывод:

Ошибка: Лицам до 18 регистрация запрещена Некорректное значение: 17

Как правильно создавать пользовательские исключения в C#

Данная статья предназначена прежде всего для новичков в мире .NET, но может быть полезна также и разработчикам с опытом, которые не до конца разобрались, как правильно строить свои user-defined exceptions с помощью C#.

Пример кода для данной статьи можно скачать здесь.

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

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

К примеру, есть метод, призванный изменять имя пользователя:

private static void EditUser(string oldUserName, string newUserName)

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

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

private static void EditUser(string oldUserNane, string newUserName)

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

Создать свой Exception не сложно – нужно определить public-класс, который будет наследоваться от System.Exception или System.ApplicationException. Хотя это и не является хорошей практикой, кода внутри созданного класса исключения можно не писать вообще:

public class UserNotFoundException : ApplicationException

От чего лучше наследоваться, от System.Exception или от System.ApplicationException?

Каждый из этих типов предназначен для конкретной цели. Тогда как System.Exception является общим классом для всех user-defined exceptions, то System.ApplicationException определяет исключения, возникающие на уровне конкретного приложения.

К примеру, тестовое приложения из данной статьи является отдельной программой, поэтому вполне допустимо наследовать определенный нами exception от System.ApplicationException.

Теперь вместо Exception мы сгенерируем созданный нами UserNotFoundException:

private static void EditUser(string oldUserNane, string newUserName)

В таком случае в качестве сообщения о возникшем исключении будет: «Error in the application.». Что не очень информативно.

  • класс исключения должен наследоваться от Exception/ApplicationException;
  • класс должен быть помечен атрибутом [System.Serializable];
  • класс должен определять стандартный конструктор;
  • класс должен определять конструктор, который устанавливает значение унаследованного свойства Message;
  • класс должен определять конструктор для обработки “внутренних исключений”;
  • класс должен определять конструктор для поддержки сериализации типа.

Немного о предназначении отдельных конструкторов: конструктор для обработки “внутренних исключений” нужен для того, чтобы передать в него exception, послуживший причиной возникновения данного исключения. Подробнее, зачем нужен конcтруктор для поддержки сериализации типа под спойлером «Добавление дополнительных полей, их сериализация и десериализация» ниже.

Дабы избавить программиста от необходимости писать одинаковый код в Visual Studio есть сниппет «Exception», который генерирует класс исключения, соответствующий всем рекомендациям, перечисленным выше.

Итак, после воплощения рекомендаций в жизнь, код нашего исключения должен выглядеть примерно так:

public class UserNotFoundException : ApplicationException < public UserNotFoundException() < >public UserNotFoundException(string message) : base(message) < >public UserNotFoundException(string message, Exception inner) : base(message, inner) < >protected UserNotFoundException(SerializationInfo info, StreamingContext context) : base(info, context) < >> 

Теперь при генерации исключения мы можем указать причину его возникновения более подробно:

throw new UserNotFoundException("User \"" + oldUserName + "\" not found in system"); 

Добавление дополнительных полей, их сериализация и десериализация

Допустим, мы хотим добавить в класс нашего исключения дополнительное поле, хранящее имя пользователя, которого хотелось найти, но в итоге он не был найден (из-за чего собственно и было сгенерировано исключение). Добавляем к классу исключения дополнительное string-поле:

[Serializable] public class UserNotFoundException : ApplicationException < private string _userNotFoundName; public string UserNotFoundName < get < return _userNotFoundName; >set < _userNotFoundName = value; >> public UserNotFoundException() < >public UserNotFoundException(string message) : base(message) < >public UserNotFoundException(string message, Exception inner) : base(message, inner) < >protected UserNotFoundException(SerializationInfo info, StreamingContext context) : base(info, context) < >> 

Проблема в том, что данные из добавленного нами поля не будут сериализоваться и десериализоваться автоматически. Мы должны позаботиться о том, чтобы CLR сериализовала и десериализовала данные по нашему исключению корректно.

Для сериализации поля мы должны переопределить метод GetObjectData, описываемый интерфейсом ISerializable. Метод GetObjectData заполняет объект SerializationInfo данными для сериализации. Именно в SerializationInfo мы должны передать имя нашего поля и информацию, хранящуюся в нем:

public override void GetObjectData(SerializationInfo info, StreamingContext context)

Метод GetObjectData для базового класса нужно вызвать для того, чтобы добавить в SerializationInfo все поля нашего исключения по умолчанию (такие как Message, TargetSite, HelpLink и т.д.).

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

protected UserNotFoundException(SerializationInfo info, StreamingContext context) : base(info, context) < if (info != null) < this._userNotFoundName = info.GetString("UserNotFoundName"); >> 

И последний штрих – добавление в XML-документацию (если вы, конечно, ее используете) нашего метода информации о том, что он может выбросить исключение определенного типа:

Итак, наш user-defined exception готов к применению. Вы можете добавить к нему все что душе угодно: дополнительные поля, описывающие состояние исключения, содержащие дополнительную информацию и т.д.

P.S.: Добавил информацию о том, как сериализовать и десериализовать дополнительные поля класса исключения. Подробности под спойлером «Добавление дополнительных полей, их сериализация и десериализация».

P.P.S: Благодарю за комментарии и здоровую критику. Тем, кто прочитал статью до конца — прочитайте также комментарии, там есть полезная информация.

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

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