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

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

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

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

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


Функция ОбщийМодуль(Имя) Экспорт
    
    Попытка
        Модуль = Вычислить(Имя);
    Исключение
        Модуль = Неопределено;
    КонецПопытки;
    
    Возврат Модуль;
    
КонецФункции

Когда разработчик выполняет этот код и смотрит значение переменной Модуль через «Табло» или окно «Вычислить выражение», колонка «Тип» отображает правильный тип (например, ОбщийМодуль.СтандартныеПодсистемыСервер), а колонка «Значение» остается абсолютно пустой. Из-за этого может сложиться ложное впечатление, что модуль «не прочитался» или вернулся некорректно.

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

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


ИмяМодуля = "СтандартныеПодсистемыСервер";
Модуль = ОбщийМодуль(ИмяМодуля);

Если Модуль <> Неопределено Тогда
    // Вызываем экспортную процедуру общего модуля
    Модуль.ИмяЭкспортногоМетода();
КонецЕсли;

Диагностика ошибок, если модуль действительно возвращает Неопределено

Если же блок Попытка ... Исключение перехватывает исключение и возвращает Неопределено, необходимо выяснить точную причину сбоя при вычислении имени модуля. Рассмотрим по шагам, как локализовать ошибку.

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

Использование готовых методов Библиотеки стандартных подсистем (БСП)

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

  1. Штатная функция получения модуля:
    
    Модуль = ОбщегоНазначенияКлиентСервер.ОбщийМодуль("СтандартныеПодсистемыСервер");
    Если Модуль <> Неопределено Тогда
        Модуль.Инициализировать();
    КонецЕсли;
    
    Эта функция корректно обрабатывает безопасный режим и возвращает готовую ссылку на общий модуль.
  2. Динамический вызов метода по имени без промежуточного получения модуля:

    Если цель заключается исключительно в том, чтобы вызвать процедуру или функцию по ее строковому имени, рекомендуется использовать методы БСП:

    
    Параметры = Новый Структура("Организация", СсылкаНаОрганизацию);
    ОбщегоНазначения.ВыполнитьМетодКонфигурации("УчетНДССервер.ЗаполнитьСтавки", Параметры);
    

    Для клиентских процедур аналогично используется процедура ОбщегоНазначенияКлиент.ВыполнитьМетодКонфигурации(...). Это делает код более надежным и защищенным от скрытых ошибок выполнения.

← На главную