В процессе разработки в среде 1С:Предприятие программисты часто сталкиваются с ситуацией, когда при определенных условиях необходимо прервать выполнение алгоритма и оповестить об этом пользователя. Начинающие разработчики нередко используют для этих целей конструкцию ВызватьИсключение. Однако это может привести к неожиданному поведению системы: вместо аккуратного окна с предупреждением программа выдает критическую ошибку и предлагает «Завершить работу» или «Перезапустить». В этой статье мы подробно разберем, почему это происходит и как реализовать корректную остановку бизнес-логики.
Разберем по шагам, что происходит в системе, когда мы пишем ВызватьИсключение в модуле объекта, например, в процедуре ОбработкаЗаполнения. Когда платформа выполняет этот код, она инициирует механизм прерывания текущего потока выполнения. Если это исключение не перехвачено блоком Попытка...Исключение, оно начинает «простреливать» весь стек вызовов вверх до самого верхнего уровня — системного ядра платформы.
Выясним причину, почему в одних случаях мы видим простое сообщение, а в других — окно перезагрузки. Все дело в транзакционном контексте и стадии инициализации объекта:
ВызватьИсключение заставляет платформу считать текущее состояние сеанса нестабильным. Чтобы не допустить повреждения данных в памяти или базе данных, система принимает решение аварийно завершить работу.ПередЗаписью, ПриЗаписи, ОбработкаПроведения) выполняются внутри неявной транзакции базы данных. Необработанное исключение внутри транзакции — это критический сбой. Платформа не может просто проигнорировать его, так как это нарушит целостность данных.Таким образом, ВызватьИсключение — это инструмент для обработки программных ошибок (например, когда отсутствует нужный файл или повреждена структура данных), а не для реализации бизнес-логики (проверка заполнения полей, наличие остатков и т.д.).
Для того чтобы штатно прервать операцию (например, создание документа на основании) и при этом не закрывать программу, в 1С предусмотрен специальный механизм. В большинстве системных событий (обработчиков) присутствует параметр Отказ типа Булево. Если установить его в значение Истина, платформа сама поймет, что операцию нужно прекратить, и сделает это максимально безопасно для интерфейса.
Рассмотрим пример кода в процедуре ОбработкаЗаполнения:
Процедура ОбработкаЗаполнения(ДанныеЗаполнения, ТекстЗаполнения, СтандартнаяОбработка)
// Проверяем условие бизнес-логики
Если ДанныеЗаполнения = Неопределено Тогда
// 1. Формируем сообщение пользователю
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Невозможно создать документ: не указаны данные для заполнения!";
Сообщение.Сообщить();
// 2. Устанавливаем флаг отказа
Отказ = Истина;
// 3. Прекращаем дальнейшее выполнение текущей процедуры
Возврат;
КонецЕсли;
// Дальнейший код заполнения...
КонецПроцедуры
В данном примере мы используем объект СообщениеПользователю, который выводит информацию в специальную панель сообщений. Установка Отказ = Истина сообщает платформе, что создание объекта должно быть отменено. При этом программа продолжит работу в штатном режиме, а пользователь просто останется в исходном окне.
Часто возникает вопрос: как быть, если проверка выполняется глубоко внутри вложенных функций, и нам нужно прервать выполнение всей цепочки вызовов? Использование ВызватьИсключение в этом случае кажется заманчивым, но, как мы выяснили, опасным.
Проанализируем правильный подход для таких ситуаций. Рекомендуется использовать функции, возвращающие результат выполнения (логическое значение или структуру), и проверять этот результат на каждом уровне вызова. Посмотрим на пример:
// Основная процедура модуля
Процедура ОбработкаЗаполнения(ДанныеЗаполнения, ТекстЗаполнения, СтандартнаяОбработка)
ЛокальныйОтказ = Ложь;
ВыполнитьСложнуюПроверку(ДанныеЗаполнения, ЛокальныйОтказ);
Если ЛокальныйОтказ Тогда
СтандартнаяОбработка = Ложь;
// Платформа обработает это как штатную отмену
Возврат;
КонецЕсли;
КонецПроцедуры
// Вложенная процедура
Процедура ВыполнитьСложнуюПроверку(Данные, Отказ)
// Вызываем еще более глубокую проверку
Если НЕ ПроверитьОстаткиНаСкладе(Данные) Тогда
ТекстОшибки = "На складе недостаточно товара!";
ОбщегоНазначенияКлиентСервер.СообщитьПользователю(ТекстОшибки);
Отказ = Истина;
Возврат;
КонецЕсли;
КонецПроцедуры
Этот метод требует дисциплины в коде, но он гарантирует стабильность работы приложения. Каждое звено в цепи вызовов «знает», что произошло что-то не так, и корректно сворачивает свою работу.
Несмотря на риски, ВызватьИсключение имеет право на жизнь, но только при соблюдении определенных условий:
Исключение выше по стеку, где оно будет обязательно перехвачено и обработано.Важный момент: Если вы все же используете ВызватьИсключение для прерывания транзакции, помните, что это всегда ведет к полному откату всех изменений, сделанных в этой транзакции, и часто сопровождается тем самым неприятным окном перезапуска, если код не был обернут в Попытка...Исключение на стороне вызывающего кода.
Чтобы избежать закрытия программы при возникновении ошибок бизнес-логики, придерживайтесь следующих правил:
СообщениеПользователю вместо текста внутри ВызватьИсключение для информирования человека.ОбработкаЗаполнения, ПередЗаписью) используйте штатный параметр Отказ = Истина.ВызватьИсключение — это «стоп-кран», который стоит дергать только в крайнем случае, когда программная логика зашла в тупик.Соблюдение этих простых рекомендаций сделает ваше решение надежным, а работу пользователей с программой — комфортной и предсказуемой.