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