Вызов исключений в коде

#std790

Область применения: управляемое приложение, мобильное приложение, обычное приложение.

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

Пример № 1. Исключение платформы с категорией ошибки ОшибкаДоступаКЛокальномуФайлу, внешний вид сообщения:

Запись журнала регистрации с событием Ошибка выполнения и комментарием:
    Ошибка при вызове метода контекста (Открыть)
    {Обработка.ПримерИсключения.Форма.Форма.Форма(14)}:Текст.Открыть("C:\not_exists_path\doc.txt");
    [ОшибкаВоВремяВыполненияВстроенногоЯзыка]
    по причине:
    Каталог не обнаружен 'C:\not_exists_path\doc.txt'
    [ОшибкаДоступаКЛокальномуФайлу]

Пример №2. Исключение платформы с категорией ошибки ПрочаяОшибка:

Запись журнала регистрации с событием Ошибка выполнения и комментарием:
    Поле объекта не обнаружено (Организация)
    {Обработка.ПримерИсключения.Форма.Форма.Форма(22)}:Если ЗначениеЗаполнено(Свойства.Организация) Тогда
    [ОшибкаВоВремяВыполненияВстроенногоЯзыка, ОшибкаИспользованияВстроенногоЯзыка]

2. Тем не менее, необходимость вызова исключений в коде все же возникает. При этом для исключений бизнес-логики, которые выводятся пользователю, категорию ошибки указывать не требуется (она соответствует ИсключениеВызванноеИзВстроенногоЯзыка). Для остальных исключений рекомендуется указывать подходящую категорию ошибки: ОшибкаРаботыСПринтером, ОшибкаСети, НарушениеПравДоступа и т.п. В этом случае в сообщении пользователю выводится не только технологический текст ошибки, но и типовые рекомендации по решению проблемы.

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

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

Например, неправильно:

Если Не РольДоступна("ПодключениеИнтернетПоддержки") Тогда
    ТекстОшибки = НСтр("ru = 'Недостаточно прав для записи данных аутентификации Интернет-поддержки.'");
    ВызватьИсключение ТекстОшибки;
КонецЕсли;

Сообщение для пользователя:

При этом запись журнала регистрации с событием Ошибка выполнения и комментарием:
    Недостаточно прав для записи данных аутентификации Интернет-поддержки.
    {Обработка.ПримерИсключения.Форма.Форма.Форма(32)}:ВызватьИсключение ТекстОшибки;
    [ОшибкаВоВремяВыполненияВстроенногоЯзыка, ИсключениеВызванноеИзВстроенногоЯзыка]

Правильно:

Если Не РольДоступна("ПодключениеИнтернетПоддержки") Тогда
    ТекстОшибки = НСтр("ru = 'Недостаточно прав для записи данных аутентификации Интернет-поддержки.'");
    ДляАдминистратора = НСтр("ru = 'Нет роли:'") + " " + Метаданные.Роли.ПодключениеИнтернетПоддержки.Представление();
    ВызватьИсключение(ТекстОшибки, КатегорияОшибки.НарушениеПравДоступа,, ДляАдминистратора);
КонецЕсли;

Сообщение для пользователя:

Автоматическая запись журнала регистрации с событием Ошибка выполнения и комментарием:
    Недостаточно прав для записи данных аутентификации Интернет-поддержки.
    {Обработка.ПримерИсключения.Форма.Форма.Форма(31)}:ВызватьИсключение(ТекстОшибки, КатегорияОшибки. НарушениеПравДоступа,, ДляАдминистратора);
    Нет роли: Подключение Интернет-поддержки
    [НарушениеПравДоступа, ОшибкаВоВремяВыполненияВстроенногоЯзыка, ИсключениеВызванноеИзВстроенногоЯзыка]

2.2. Для диагностики программных ошибок, например, когда из вызывающего кода передано некорректное значение входного параметра, некорректно встроена подсистема и т.п., рекомендуется вызывать исключение с категорией ОшибкаКонфигурации. Такие ошибки предназначены для разработчиков, а не для пользователей; они выявляются и исправляются при отладке и тестировании продукта. В этом случае выводится стандартное сообщение «К сожалению, возникла непредвиденная ошибка» с предложением сформировать отчет об ошибке и отправить его разработчику. 

Пример:

Если ТипЗнч(Количество) <> Тип(«Число») Тогда
    ТекстОшибки = НСтр("ru = 'Недопустимое значение параметра'") + " " + "Количество";
    ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации);
КонецЕсли;

Сообщение:

Запись журнала регистрации с событием Ошибка выполнения и комментарием:
    Недопустимое значение параметра Количество
    {Обработка.ПримерИсключения.Форма.Форма.Форма(40)}:ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации);
    [ОшибкаВоВремяВыполненияВстроенногоЯзыка, ИсключениеВызванноеИзВстроенногоЯзыка, ОшибкаКонфигурации]

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

2.3.1. Пример обработки кодов ошибок вместо вызова исключения:

РезультатЗагрузки = ЗагрузитьФайлИзИнтернета(...);
Если РезультатЗагрузки = "Успешно" Тогда 
...
ИначеЕсли ...

2.3.2. Пример анализа категории ошибки в исключении, которое вызвано в методе платформе:

НомерПопытки = 1;
Пока НомерПопытки < 4 Цикл
    Попытка
        HTTPОтвет = HTTPСоединение.ОтправитьДляОбработки(HTTPЗапрос);
    Исключение
        ИнформацияОбОшибке = ИнформацияОбОшибке();
        Если ИнформацияОбОшибке.ЯвляетсяОшибкойКатегории(КатегорияОшибки.ОшибкаСети) Тогда
            НомерПопытки = НомерПопытки + 1;
            Продолжить;
        КонецЕсли;
        ВызватьИсключение;
    КонецПопытки;
КонецЦикла;

2.3.3. Пример вызова метода ВызватьИсключение со строковым кодом ошибки:

Если КонфигурацияБазыДанныхИзмененаДинамически() Тогда
    ВызватьИсключение(НСтр("ru = 'Версия приложения обновлена, требуется перезапустить сеанс.'"),,
        "СтандартныеПодсистемы.БазоваяФункциональность.КонфигурацияИзмененаДинамически");
КонецЕсли;

Для уникальности кодов ошибок в них рекомендуется включать префикс подсистемы, в которой вызывается исключение, например:
"СтандартныеПодсистемы.БазоваяФункциональность.КонфигурацияИзмененаДинамически",
"СтандартныеПодсистемы.БазоваяФункциональность.РасширенияИзмененыДинамически".

Пример обработки исключения со строковым кодом ошибки:

Попытка
    ВыполнитьОбновление();
Исключение
    КодОшибки = ИнформацияОбОшибке().Код;
    Если КодОшибки = "СтандартныеПодсистемы.БазоваяФункциональность.КонфигурацияИзмененаДинамически"
     Или КодОшибки = "СтандартныеПодсистемы.БазоваяФункциональность.РасширенияИзмененыДинамически" Тогда
        ПерезапуститьЗаданиеОбновления();
        Возврат;
    КонецЕсли;
    ВызватьИсключение;
КонецПопытки;

При использовании в конфигурации Библиотеки стандартных подсистем (БСП) для обработки кодов ошибок в исключениях рекомендуется вызывать функцию ЭтоИсключениеСКодомОшибки общего модуля ОбщегоНазначенияКлиентСервер. Она находит один или несколько интересующих кодов ошибок рекурсивно во всех вложенных исключениях (в свойстве ИнформацияОбОшибке.Причина), что удобно, когда исключение перевызывается по стеку. Пример:

Попытка
    ВыполнитьОбновление();
Исключение
    Если ОбщегоНазначенияКлиентСервер.ЭтоИсключениеСКодомОшибки(ИнформацияОбОшибке(),
            "СтандартныеПодсистемы.БазоваяФункциональность.КонфигурацияИзмененаДинамически
            |СтандартныеПодсистемы.БазоваяФункциональность.РасширенияИзмененыДинамически") Тогда
        ПерезапуститьЗаданиеОбновления();
        Возврат;
    КонецЕсли;
    ВызватьИсключение;
КонецПопытки;

3. Неприемлемо в событиях ОбработкаПроверкиЗаполнения, ОбработкаПроведения, ПередЗаписью, ПриЗаписи, ПередУдалением и т.п. вызывать исключения для выдачи останавливающих предупреждений, которые должен отработать пользователь. Вместо этого следует устанавливать параметр Отказ в значение Истина и выводить сообщения пользователю. Тем самым пользователь увидит все блокирующие причины остановки сразу, а не по очереди. 

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

Процедура ПередЗаписью(Отказ)
    Если Не ЗарегистрироватьИзмененияНаУзлахПлановОбмена() Тогда 
        ТекстОшибки = НСтр("ru = 'Не удалось зарегистрировать изменения на узлах планов обмена. Обратитесь к администратору.'");
        ВызватьИсключение ТекстОшибки;
    КонецЕсли; 
      ...  
КонецПроцедуры

Подробнее см. пп. 1.1 и 1.3 стандарта Информирование пользователя.