Как вызвать процедуру модуля объекта по имени, хранящемуся в переменной?

Программист 1С v8.3 (Обычные формы) IT и автоматизация бизнеса
← На главную

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

Способ 1. Использование оператора Выполнить (Execute)

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

Представим ситуацию: у нас есть объект документа, и в переменной ИмяПФ хранится название экспортной процедуры из его модуля объекта (например, "ПечатьТОРГ12"). Нам нужно передать в эту процедуру параметр — сам документ или таблицу значений.

Разберем по шагам, как сформировать строку для выполнения:


// Пусть ИмяПФ = "ПечатьТОРГ12"
// пЭтотОбъект — это ссылка на объект документа или сам объект
// пДокумент — параметр, который нужно передать в процедуру

СтрокаВызова = "пЭтотОбъект." + ИмяПФ + "(пДокумент)";
Выполнить(СтрокаВызова);

Важный нюанс: при использовании Выполнить все переменные, которые упоминаются внутри строки (в нашем примере это пЭтотОбъект и пДокумент), должны быть доступны в том же программном контексте, где вызывается сам оператор Выполнить. Если вы ошибетесь в написании имени переменной внутри строки, система выдаст ошибку о том, что переменная не определена.

Способ 2. Получение результата через Вычислить (Eval)

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

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


ИмяФункции = "ПолучитьМакетПечати";
ПараметрПечати = "Стандартный";

// Вызываем функцию и сохраняем результат в переменную
ТабДок = Вычислить("пЭтотОбъект." + ИмяФункции + "(ПараметрПечати)");

Если ТабДок <> Неопределено Тогда
    ТабДок.Показать();
КонецЕсли;

Преимущество Вычислить перед Выполнить("Результат = ...") заключается в более лаконичном коде и чуть более высокой скорости работы в некоторых сценариях, так как системе не нужно обрабатывать операцию присваивания как часть исполняемого кода.

Способ 3. Безопасный вызов через методы БСП

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

Выясним, какие альтернативы предлагает БСП. В модуле ОбщегоНазначения часто присутствуют методы для безопасного выполнения кода (подробнее см. в справочнике по методам БСП). Рассмотрим пример использования:


// Пример использования БСП для выполнения метода
// Позволяет избежать прямого выполнения потенциально опасного кода
ОбщегоНазначения.ВыполнитьМетодОбъекта(Объект, "ИмяПроцедуры", Параметры);

Если ваше решение предназначено для работы в защищенном режиме, используйте ОбщегоНазначения.ВыполнитьВБезопасномРежиме(). Это гарантирует, что динамический код не нарушит права доступа и политики безопасности системы.

Способ 4. Паттерн «Распределитель» (Router) — самый быстрый метод

Проанализируем ситуацию с точки зрения производительности. Главный минус Выполнить — это необходимость компиляции строки кода при каждом вызове. Если вы вызываете динамическую процедуру внутри цикла на 10 000 итераций, время выполнения значительно увеличится.

Вместо динамического выполнения рассмотрим создание "шлюза" в модуле объекта. Это экспортная процедура, которая принимает имя метода и параметры, а затем через конструкцию Если...ИначеЕсли вызывает нужный метод.


// В модуле объекта документа:
Процедура ВыполнитьПечатьПоИмени(ИмяМетода, Параметр) Экспорт
    Если ИмяМетода = "ПечатьТТН" Тогда
        ПечатьТТН(Параметр);
    ИначеЕсли ИмяМетода = "ПечатьТорг12" Тогда
        ПечатьТорг12(Параметр);
    Иначе
        ВызватьИсключение "Метод не найден!";
    КонецЕсли;
КонецПроцедуры

Преимущества этого подхода:

  1. Высокая скорость: код компилируется один раз при загрузке модуля.
  2. Типизация: вы сразу видите, какие методы доступны.
  3. Отладка: вы можете легко поставить точку останова и зайти внутрь конкретной процедуры, что невозможно при использовании Выполнить.

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

Рассмотрим критические моменты, которые нужно учитывать при реализации подобных механизмов:

1. Отладка и поиск ошибок. Посмотрим на проблему с позиции сопровождения кода. Ошибки внутри строки Выполнить крайне трудно диагностировать. Если в вызываемой процедуре произойдет сбой, стек вызовов может указывать на саму строку выполнения, не давая подробностей о месте возникновения ошибки внутри динамического кода. Всегда оборачивайте такие вызовы в блок Попытка...Исключение.


Попытка
    Выполнить("Объект." + ИмяПроцедуры + "()");
Исключение
    ЗаписьЖурналаРегистрации("Ошибка динамического вызова",
        УровеньЖурналаРегистрации.Ошибка,,, 
        ОписаниеОшибки());
    Сообщить("Не удалось выполнить команду печати.");
КонецПопытки;

2. Контекст исполнения. Помните, что оператор Выполнить исполняется в том контексте, где он вызван. Если вы вызываете его в общем модуле, то у вас не будет доступа к переменной ЭтаФорма или ЭтотОбъект, если вы не передали их туда явно.

3. Проблемы с 1С:Fresh и профилями безопасности. В облачных инфраструктурах использование Выполнить часто блокируется на уровне платформы. Если вы разрабатываете расширение для работы в сервисе 1С:Фреш, вам придется либо отказаться от этого метода в пользу статических вызовов (Способ 4), либо регистрировать опасные операции в профиле безопасности через администратора сервиса.

4. Типизация параметров. При формировании строки для Выполнить старайтесь не передавать значения "внутри" строки (через конкатенацию), если это не простые строки или числа. Ссылки, структуры и таблицы значений лучше передавать как имена существующих в контексте переменных, как мы разбирали в Способе 1. Это исключит ошибки преобразования типов в строку.

Подведем итог: использование Выполнить — это мощный, но опасный инструмент. Для простых разовых задач в обычных формах (как в случае с Альфа-Авто) он подходит идеально. Для высоконагруженных систем или современных облачных решений лучше использовать безопасные методы БСП или структуру Если...ИначеЕсли.

← На главную