К статье
Практический материал

Разработка и Конфигурация · 12 мин

Процедура как параметр в 1С: передача и вызов обработчиков

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

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

Выбор механизма зависит от контекста: клиент или сервер, управляемые или обычные формы, синхронный или асинхронный вызов. Ошибка в выборе приводит либо к исключению «Метод объекта не обнаружен», либо к тому, что обработчик просто не выполняется молча.

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

Какие механизмы заменяют «функцию как параметр» в 1С

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

Первый механизм — ОписаниеОповещения. Это объект, который хранит имя процедуры, модуль, в котором она находится, и дополнительные параметры. Платформа сама вызывает указанную процедуру, когда наступает событие: закрытие формы, ответ пользователя в диалоге, завершение помещения файла. Объект можно передать как параметр в другую процедуру — это и есть полноценный «колбэк».

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

Сравнение вариантов

ОписаниеОповещения

Типизированный объект, поддерживает дополнительные параметры, работает в асинхронных сценариях. Ограничение: вызываемая процедура должна быть экспортной и принимать заданную сигнатуру параметров.

Выполнить с именем строкой

Гибко, работает на сервере и в общих модулях. Ограничение: нет проверки на этапе компиляции, риск ошибки «Метод не обнаружен», не работает в некоторых клиентских контекстах.

Передача модуля + имени

Комбинация: передаёте и объект модуля (например, форму), и имя процедуры, затем вызываете через точку. Подходит для обратных вызовов в формы.

ОписаниеОповещения: передача обработчика как параметра

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

&НаКлиенте

Процедура ПоказатьПодтверждение(Команда)

ДополнительныеПараметры = Новый Структура("ИдентификаторСтроки", 42);

Оповещение = Новый ОписаниеОповещения(

"ПослеПодтвержденияУдаления", ЭтотОбъект, ДополнительныеПараметры);

ПоказатьВопрос(Оповещение, "Удалить выбранную строку?",

РежимДиалогаВопрос.ДаНет);

КонецПроцедуры

&НаКлиенте

Процедура ПослеПодтвержденияУдаления(Результат, ДополнительныеПараметры) Экспорт

Если Результат = КодВозвратаДиалога.Да Тогда

УдалитьСтрокуНаСервере(ДополнительныеПараметры.ИдентификаторСтроки);

КонецЕсли;

КонецПроцедуры

Обратите внимание на слово Экспорт: процедура-обработчик обязана быть экспортной, иначе платформа не сможет вызвать её извне модуля. Это одна из самых частых причин ошибки «Процедура не обнаружена».

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

Передача ОписаниеОповещения в собственные процедуры

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

&НаКлиенте

Процедура ВыполнитьОбменССервисом(ОповещениеОЗавершении) Экспорт

Результат = ВыполнитьОбменНаСервере();

// После завершения вызываем переданный обработчик

ВыполнитьОбработкуОповещения(ОповещениеОЗавершении, Результат);

КонецПроцедуры

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

Если ОповещениеОЗавершении <> Неопределено Тогда

ВыполнитьОбработкуОповещения(ОповещениеОЗавершении, Результат);

КонецЕсли;

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

Порядок действий при создании обратного вызова
  1. 1
    Объявите экспортную процедуру-обработчик с сигнатурой (Результат, ДополнительныеПараметры)
  2. 2
    Создайте ОписаниеОповещения с именем обработчика и владельцем
  3. 3
    Передайте объект оповещения параметром в вызываемую процедуру
  4. 4
    В вызываемой процедуре проверьте оповещение на Неопределено
  5. 5
    Вызовите ВыполнитьОбработкуОповещения и проверьте, что обработчик сработал

Вызов процедуры по имени: метод Выполнить

На сервере, где оповещения недоступны, процедуру как параметр передают строкой с именем. Метод Выполнить исполняет произвольный фрагмент кода, поэтому имя подставляется прямо в строку вызова.

&НаСервере

Процедура ОбработатьДокументы(ИмяПроцедурыОбработки) Экспорт

Для Каждого ДокументСсылка Из СписокДокументов Цикл

Выполнить(ИмяПроцедурыОбработки + "(ДокументСсылка)");

КонецЦикла;

КонецПроцедуры

Если вызываемая процедура находится в общем модуле, имя указывается полностью: "ОбщегоНазначения.ОбработатьДокумент(ДокументСсылка)". Процедура при этом должна быть экспортной, а модуль — серверным.

Главный недостаток подхода — отсутствие контроля на этапе разработки. Опечатка в имени, неверное число параметров или недоступность модуля в текущем контексте обнаружатся только при выполнении. Поэтому имя процедуры лучше не собирать из пользовательского ввода, а выбирать из фиксированного списка допустимых значений.

Обратный вызов из общего модуля в форму

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

На клиенте — через ОписаниеОповещения

Если общий модуль клиентский, передайте ему готовое описание оповещения, созданное в форме. Модуль вызовет обработчик стандартно через ВыполнитьОбработкуОповещения. Это предпочтительный вариант: связь явная, параметры типизированы.

На сервере — результат возвращается, а не вызывается

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

Маршрут решения

Как выбрать механизм

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

Типичные ошибки и их диагностика

Ошибка «Процедура или функция с указанным именем не определена» при работе с оповещением почти всегда означает одно из трёх: забыто слово Экспорт, неверно указан владелец (например, ЭтотОбъект вместо общего модуля) или опечатка в имени. Проверяйте эти три пункта в первую очередь.

Вторая группа проблем — несовпадение сигнатуры. Обработчик закрытия формы получает результат закрытия и дополнительные параметры; обработчик вопроса — код возврата диалога. Если обработчик объявлен без параметров, а платформа передаёт два, вызов упадёт. Держите под рукой сигнатуру, которую ожидает конкретный метод платформы.

Третья группа — контекст. Процедура в модуле с директивой &НаСервере недоступна для клиентского оповещения, а метод в модуле без контекста не может быть обработчиком. Директивы компиляции должны совпадать с местом вызова.

Типичные ошибки
01
Обработчик объявлен без Экспорт — платформа не находит процедуру при вызове оповещения
02
Неверный владелец в конструкторе ОписаниеОповещения — обработчик ищется не в том модуле
03
Вызов ВыполнитьОбработкуОповещения без проверки на Неопределено — исключение при опциональном параметре
04
Имя процедуры для Выполнить собирается из внешних данных — риск исполнения произвольного кода
05
Обработчик размещён в серверной процедуре формы, а оповещение создаётся на клиенте — контексты не пересекаются

Альтернативы: подписки на события и переопределяемые модули

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

Переопределяемые общие модули — приём из библиотеки стандартных подсистем: базовый модуль вызывает процедуру из модуля с суффиксом «Переопределяемый», который разработчик заполняет под свои нужды. Это устойчивый к обновлениям способ внедрения логики.

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

Контрольные точки

Как проверить результат

Экспортность обработчика
Норма

В объявлении процедуры есть слово Экспорт, оповещение срабатывает

Тревожный признак

Ошибка «Процедура не обнаружена» при вызове

Сигнатура обработчика
Норма

Параметры соответствуют документации вызывающего метода

Тревожный признак

Ошибка несоответствия числа параметров

Директива компиляции
Норма

Обработчик находится в клиентском контексте для клиентских оповещений

Тревожный признак

Оповещение не вызывается или падает с ошибкой контекста

Источник имени для Выполнить
Норма

Имя выбирается из фиксированного списка в коде

Тревожный признак

Имя приходит из пользовательского ввода или внешнего источника

Итог

Что важно запомнить

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

Частые вопросы

Можно ли передать функцию как параметр и получить её результат?

Напрямую — нет. Для оповещений результат возвращается через вызов обработчика, а не через возвращаемое значение. На сервере функцию по имени можно вызвать через Вычислить: Результат = Вычислить("МойМодуль.МояФункция(Параметр)"). Функция должна быть экспортной, а выражение должно возвращать значение.

Почему обработчик оповещения не вызывается, хотя ошибок нет?

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

Можно ли передать дополнительные параметры в обработчик оповещения?

Да. Третий параметр конструктора ОписаниеОповещения принимает произвольное значение — обычно структуру. Оно будет передано вторым параметром в обработчик. Типовой результат (например, ответ диалога) всегда приходит первым параметром.

Работает ли Выполнить в тонком и веб-клиенте?

Метод Выполнить в клиентских контекстах управляемого приложения недоступен — это ограничение безопасности платформы. В тонком и веб-клиенте для обратных вызовов используйте только ОписаниеОповещения. Выполнить применяйте на сервере и в толстом клиенте обычного приложения.

Как отладить вызов обработчика через оповещение?

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

Чем заменить передачу процедуры при обновляемой типовой конфигурации?

Используйте подписки на события, переопределяемые модули БСП или расширения конфигурации с аннотациями &После и &Вместо. Эти механизмы не требуют изменения типового кода и сохраняются при обновлении, в отличие от встраивания вызовов по имени в типовые модули.