Почему при вызове функции общего модуля возникает ошибка «Значение не является значением объектного типа»?

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

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

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

Выясним причину: механизм затенения идентификаторов

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

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

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


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

Как быстро локализовать проблему

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

  1. Проверка типа в окне табло: установим точку останова на проблемной строке. Добавим в табло выражение ТипЗнч(ИмяМодуля). Если результат вычисления возвращает Строка, Неопределено или ссылку на элемент управления вместо ОбщийМодуль, имя однозначно перекрыто локальным контекстом.
  2. Поиск совпадающих имен в конфигураторе: выполним встроенную проверку конфигурации через меню Конфигурация → Проверка конфигурации. Обязательно отметим флаг «Поиск совпадающих имен». Платформа выведет полный отчет обо всех совпадениях имен общих модулей с реквизитами и переменными объектов.
  3. Статический анализ: если используются современные средства разработки и проверки качества кода (BSL Language Server, SonarQube), они подсвечивают правило затенения имен (variable shadowing) в момент написания кода.

Способ 1. Приведение имен модулей к стандартам разработки 1С

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

Общие модули должны иметь суффиксы, определяющие контекст их исполнения и назначение:

  1. ИмяПодсистемыКлиент — для процедур, выполняемых исключительно на стороне клиента.
  2. ИмяПодсистемыСервер или ИмяПодсистемыВызовСервера — для серверных алгоритмов.
  3. ИмяПодсистемыКлиентСервер — для универсальных методов обработки данных.
  4. ИмяПодсистемыПереопределяемый — для переопределяемой логики внедряемых подсистем.

Переименование модуля из НазначениеПлатежа в НазначениеПлатежаКлиентСервер полностью исключает риск коллизии имен с реквизитами любых прикладных объектов.

Способ 2. Явное разделение контекста при обращении к реквизитам

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


// Обращение к реквизиту текущего объекта в модуле документа или обычной форме:
ТекстНазначения = ЭтотОбъект.НазначениеПлатежа;

// В управляемой форме:
ТекстНазначения = Объект.НазначениеПлатежа;

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

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


// Безопасное получение серверного модуля:
МодульСервер = ОбщегоНазначения.ОбщийМодуль("НазначениеПлатежа");
Результат = МодульСервер.ПолучитьКомментарий(ДокументЗаказПоставщику, СуммаДокумента);

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

Способ 4. Динамическое получение контекста общего модуля через функцию «Вычислить»

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


// Получаем доступ к общему модулю в обход локальных реквизитов документа:
СсылкаНаМодуль = Вычислить("НазначениеПлатежа");
л_Комментарий = СсылкаНаМодуль.ПолучитьКомментарий(ДокументЗаказПоставщику, СуммаДокумента);

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

← На главную