Разработка и Конфигурация · 11 мин
1С: передача функции как параметра — приёмы и примеры
Как передать функцию как параметр в 1С: ОписаниеОповещения, Выполнить, методы через строковые имена, типовые ошибки и приёмы для управляемых форм.
Во встроенном языке 1С нельзя напрямую присвоить функцию переменной и передать её как объект, как в JavaScript или Python. Однако задача «вызвать код, который заранее неизвестен» решается штатными механизмами платформы: описанием оповещения, методом Выполнить, вызовом метода формы или объекта по строковому имени и параметризуемыми обработчиками. Понимание этих инструментов позволяет строить гибкие обработчики событий, универсальные процедуры обхода коллекций и асинхронные сценарии.
Выбор подхода зависит от контекста: клиент или сервер, толстый или тонкий клиент, управляемая форма или фоновое задание. Неправильно выбранный механизм приводит либо к ошибкам компиляции, либо к потере контекста выполнения — например, когда обработчик оповещения не видит переменные вызывающей процедуры.
Какие механизмы заменяют функцию-параметр в 1С
Платформа 1С предлагает четыре основных способа передать «действие» в другую процедуру:
- ОписаниеОповещения — объект, хранящий имя процедуры-обработчика, модуль, в котором она находится, и дополнительные параметры. Используется в асинхронных методах (ПоказатьВопрос, ОткрытьФорму, НачатьПомещениеФайла) и может передаваться между процедурами как обычное значение.
- Выполнить(ТекстКода) — исполняет произвольный фрагмент кода на встроенном языке, включая вызов процедуры по имени.
- Вызов метода по строковому имени — конструкция вида
Объект[ИмяМетода](Параметры)для форм, обработок и объектов с методами. - Строковое имя процедуры + ветвление — передача имени как строки и явный вызов через Если/ИначеЕсли, что безопасно, но громоздко.
Сравнение вариантов
Типизированный, проверяемый, работает на клиенте и сервере. Ограничение: обработчик должен быть экспортной процедурой в указанном модуле.
Универсален, но не проверяется компилятором, медленнее и опасен при передаче пользовательского ввода.
Подходит для форм и обработок; ошибка имени проявится только в рантайме.
Полностью контролируемо и безопасно, но требует правки кода при добавлении нового обработчика.
ОписаниеОповещения: основной способ
Конструктор Новый ОписаниеОповещения(ИмяПроцедуры, Модуль, ДополнительныеПараметры, ИмяПроцедурыОшибки, МодульОшибки) создаёт объект, который можно хранить в переменной, передавать в процедуры и активировать позже через ВыполнитьОбработкуОповещения.
&НаКлиенте
Процедура ОбработатьДанные(Данные, ОповещениеОЗавершении) Экспорт
// ... логика обработки ...
Результат = Данные * 2;
ВыполнитьОбработкуОповещения(ОповещениеОЗавершении, Результат);
КонецПроцедуры
&НаКлиенте
Процедура КомандаЗапустить(Команда)
Оповещение = Новый ОписаниеОповещения("ПослеОбработки", ЭтотОбъект);
ОбработатьДанные(21, Оповещение);
КонецПроцедуры
&НаКлиенте
Процедура ПослеОбработки(Результат, ДополнительныеПараметры) Экспорт
ПоказатьПредупреждение(, "Итог: " + Результат);
КонецПроцедуры
Обработчик обязательно должен быть экспортным и иметь сигнатуру (Результат, ДополнительныеПараметры). Если процедура объявлена без директивы Экспорт, вызов завершится ошибкой «Метод объекта не обнаружен» уже в момент выполнения, а не при сохранении модуля.
ОписаниеОповещения в общих модулях
Если обработчик находится в общем клиентском модуле, во втором параметре конструктора указывается сам модуль: Новый ОписаниеОповещения("ОбработатьОтвет", ОбщегоНазначенияКлиент). Модуль должен быть доступен в том же контексте, где будет выполняться оповещение: серверный модуль нельзя вызвать из клиентского оповещения.
Передача обработчика в асинхронные методы
Наиболее частый сценарий — вложенные асинхронные вызовы. Каждый метод платформы с префиксом «Начать» или «Показать» принимает описание оповещения первым параметром. Передавая его дальше по цепочке, вы строите последовательность шагов без блокировки интерфейса.
&НаКлиенте
Процедура ПоказатьВопросЗавершение(Результат, ДополнительныеПараметры) Экспорт
Если Результат = КодВозвратаДиалога.Да Тогда
ПродолжитьСохранение(ДополнительныеПараметры.ИмяФайла);
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура СпроситьИСохранить(ИмяФайла)
Парам = Новый Структура("ИмяФайла", ИмяФайла);
Оповещение = Новый ОписаниеОповещения("ПоказатьВопросЗавершение", ЭтотОбъект, Парам);
ПоказатьВопрос(Оповещение, "Сохранить файл?", РежимДиалогаВопрос.ДаНет);
КонецПроцедуры
Ключевой признак корректной реализации: после закрытия вопроса управление возвращается именно в ваш обработчик, а дополнительные параметры доступны без обращения к реквизитам формы, которые к этому моменту могли измениться.
- 1Объявите экспортную процедуру-обработчик с параметрами (Результат, ДополнительныеПараметры).
- 2Создайте ОписаниеОповещения, указав имя обработчика и модуль (ЭтотОбъект для формы).
- 3При необходимости передайте структуру с контекстом в третий параметр конструктора.
- 4Передайте описание оповещения в процедуру или асинхронный метод.
- 5Проверьте в отладчике, что обработчик вызывается и получает ожидаемый результат.
Метод Выполнить и вызов по строковому имени
Метод Выполнить исполняет строку как код. Типичное применение — вызов процедуры, имя которой хранится в настройках или регистре:
ИмяПроцедуры = "МойОбработчик";
Выполнить(ИмяПроцедуры + "(Параметры);");
Для форм удобнее вызов по имени без Выполнить:
Форма = ПолучитьФорму("Обработка.МояОбработка.Форма");
Форма["ЗаполнитьДанные"](ПараметрыЗаполнения);
Оба подхода имеют общее ограничение: компилятор не проверяет существование метода, поэтому опечатка в имени обнаружится только при выполнении. Кроме того, Выполнить недоступен в некоторых контекстах (например, в безопасном режиме и при определённых настройках), а исполнение строки, собранной из пользовательского ввода, — прямой путь к уязвимости инъекции кода.
Типовой сценарий: универсальная процедура обхода коллекции
Передача «действия» как параметра позволяет вынести повторяющийся обход в одну процедуру, а специфику — в обработчик:
&НаКлиенте
Процедура ДляКаждойСтроки(Таблица, ОповещениеНаСтроку) Экспорт
Для Каждого Строка Из Таблица Цикл
ВыполнитьОбработкуОповещения(ОповещениеНаСтроку, Строка);
КонецЦикла;
КонецПроцедуры
&НаКлиенте
Процедура ОтметитьСтроку(Строка, ДопПараметры) Экспорт
Строка.Пометка = Истина;
КонецПроцедуры
Такой приём упрощает тестирование: обход проверяется один раз, а обработчики подменяются. Помните, что на тонком клиенте синхронный вызов оповещения выполняется немедленно — «асинхронным» его делает только вызывающий код.
Если обработчику нужно вернуть значение обратно в вызывающий код, передавайте в ДополнительныеПараметры структуру и заполняйте её поля внутри обработчика — структура передаётся по ссылке, и изменения будут видны снаружи.
Частые ошибки и их диагностика
Большинство проблем при передаче функций-параметров сводится к нескольким повторяющимся причинам:
- Обработчик не экспортный — ошибка «Метод объекта не обнаружен» при вызове оповещения.
- Неверная сигнатура: обработчик объявлен без параметров, а платформа передаёт результат и дополнительные параметры — возникает ошибка несоответствия числа параметров.
- Описание оповещения создано для модуля формы, но вызов происходит после закрытия формы — обращение к уничтоженному объекту.
- Использование
Выполнитьна тонком клиенте для вызова серверной процедуры — контекст сервера недоступен, код падает. - Передача описания оповещения на сервер через вызов
&НаСервере-метода — ОписаниеОповещения не сериализуется, такой параметр передать нельзя.
Проверка результата и ограничения
После внедрения механизма проверьте три вещи: обработчик реально вызывается (точка останова или сообщение), получает ожидаемый результат и видит дополнительные параметры. Если обработчик не срабатывает, первым делом убедитесь, что форма-владелец ещё открыта, а имя процедуры указано без опечаток и без скобок.
Как проверить результат
Точка останова в обработчике срабатывает после завершения операции
Обработчик молча не вызывается — проверьте имя и директиву Экспорт
Структура содержит все переданные поля
Неопределено — оповещение создано без третьего параметра
ЭтотОбъект доступен внутри обработчика
Ошибка обращения к реквизитам — форма уже закрыта
Ограничения, которые важно помнить: ОписаниеОповещения живёт только в рамках сеанса и контекста, в фоновых заданиях недоступно; внешние компоненты и расширения имеют свои правила для экспорта обработчиков; в обычных формах (толстый клиент) механизм оповещений частично отличается от управляемых.
Что важно запомнить
Роль «функции как параметра» в 1С выполняет ОписаниеОповещения: экспортный обработчик, модуль-владелец и дополнительные параметры. Выполнить и вызов по строковому имени — запасные варианты с рисками, применимые только к доверенному коду. Серверной передачи оповещений не существует.
Частые вопросы
Можно ли передать функцию (с возвратом значения), а не процедуру?
ОписаниеОповещения вызывает процедуру, и её возвращаемое значение игнорируется. Чтобы получить результат обратно, передайте в ДополнительныеПараметры структуру и запишите итог в её поле — изменения будут видны вызывающему коду.
Работает ли ОписаниеОповещения на сервере?
Объект можно создать на сервере, но передать его между клиентом и сервером нельзя — он не сериализуется. Серверная логика обычно возвращает результат клиенту, а клиент уже решает, какое оповещение выполнить.
Чем заменить Выполнить, если он запрещён политикой безопасности?
Используйте соответствие «имя → ветка кода»: храните допустимые имена в фиксированном списке и вызывайте конкретные процедуры через Если/ИначеЕсли. Это безопаснее и проверяется при компиляции модуля.
Почему обработчик оповещения не видит локальные переменные вызывающей процедуры?
Обработчик выполняется в собственном контексте после завершения вызывающей процедуры. Все нужные данные передавайте явно — через третий параметр конструктора ОписаниеОповещения или реквизиты объекта.
Можно ли использовать обработчик из модуля другой формы?
Да, если передать ссылку на ту форму как модуль в конструкторе и форма останется открытой к моменту вызова. На практике надёжнее размещать общие обработчики в клиентском общем модуле — он не зависит от жизненного цикла форм.
Как отладить цепочку вложенных оповещений?
Расставьте точки останова в каждом обработчике и в месте вызова ВыполнитьОбработкуОповещения. Если цепочка обрывается, проверьте, что каждый промежуточный обработчик создаёт и передаёт следующее оповещение, а не завершается без продолжения.