В процессе разработки в среде 1С:Предприятие одной из самых часто встречающихся ошибок является сообщение: «Значение не является значением объектного типа». Эта проблема возникает, когда программный код пытается обратиться к свойству или методу через точку от переменной, которая не содержит объект или ссылку. Рассмотрим детально, почему это происходит, как диагностировать проблему и какие методы решения считаются наиболее правильными и производительными.
Проанализируем классическую ситуацию: нам необходимо получить адрес электронной почты руководителя конкретного пользователя. Типичный, но потенциально опасный код выглядит следующим образом:
Автор = Справочники.Пользователи.НайтиПоНаименованию("Иванов Иван Иванович");
Руководитель = Автор.Руководитель;
Почта = Руководитель.Почта;
Ошибка возникает на этапе Руководитель.Почта. Выясним причину: если переменная Руководитель по какой-то причине приняла значение Неопределено, NULL или простое число/строку, система не может «заглянуть внутрь» этого значения, чтобы найти там поле Почта. В 1С обращение через точку допустимо только к объектам (например, документам, справочникам) или их ссылкам.
Важно помнить разницу в поведении системы:
НайтиПоНаименованию не находит объект, он возвращает Пустую ссылку. Обращение к реквизиту пустой ссылки (Автор.Руководитель) не вызовет мгновенную ошибку, но вернет значение по умолчанию (в данном случае — еще одну пустую ссылку руководителя).NULL (например, в результате запроса с левым соединением) или Неопределено, любая попытка обращения через точку приведет к аварийному завершению работы алгоритма.Прежде чем менять код, проанализируем состояние данных. Остановимся отладчиком на строке, где происходит присвоение, и воспользуемся инструментом «Табло» или «Вычислить выражение».
Проверим типы данных следующими командами:
ТипЗнч(Автор) — убедимся, что это действительно ссылка на справочник.ТипЗнч(Автор.Руководитель) — если здесь мы видим Null или Неопределено, значит, мы нашли источник проблемы..Почта должно вернуть пустую строку, а не ошибку. Если ошибка все же есть, значит, сама переменная Руководитель была переопределена ранее в коде.Рассмотрим ситуацию, с которой столкнулся автор темы. Иногда визуальное название поля на форме не совпадает с его именем в метаданных. В справочнике «Пользователи» часто используется иерархия. Рассмотрим структуру:
В ходе анализа выяснилось, что реквизит Руководитель был заполнен не у самого пользователя, а у его подразделения (Родителя). Таким образом, прямой путь Автор.Руководитель возвращал пустую ссылку, а данные находились по адресу Автор.Родитель.Руководитель.
Совет: Всегда проверяйте в конфигураторе, к какому именно объекту относится реквизит. Если данные привязаны к отделу, ваш код должен учитывать вложенность.
Для того чтобы программа не «падала» при встрече с пустыми значениями, в современных конфигурациях (УТ 11, ERP, БП 3.0) крайне рекомендуется использовать функции Библиотеки стандартных подсистем (БСП). Разберем использование функции ЗначениеРеквизитаОбъекта.
Этот метод позволяет получить данные «одним махом», даже если путь включает несколько точек:
Автор = Справочники.Пользователи.НайтиПоНаименованию("Иванов Иван Иванович");
// Безопасное получение почты руководителя через Родителя
Почта = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Автор, "Родитель.Руководитель.Почта");
Почему это лучше прямого обращения?
Родитель или Руководитель окажутся не заполнены (пустая ссылка), функция не выдаст ошибку, а просто вернет пустое значение конечного типа (пустую строку для почты).Автор.Родитель.Руководитель.Почта платформа может выполнить несколько неявных запросов к базе данных. Функция БСП оптимизирует этот процесс, выполняя один эффективный SQL-запрос.Если нам нужно получить данные для логики приложения, наиболее профессиональным подходом будет использование объекта Запрос. Это гарантирует максимальную скорость работы и корректную обработку NULL.
Рассмотрим пример запроса:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ЕСТЬNULL(Пользователи.Родитель.Руководитель.Почта, """") КАК ПочтаРуководителя
|ИЗ
| Справочник.Пользователи КАК Пользователи
|ГДЕ
| Пользователи.Ссылка = &СсылкаПользователя";
Запрос.УстановитьПараметр("СсылкаПользователя", Автор);
РезультатЗапроса = Запрос.Выполнить();
Если НЕ РезультатЗапроса.Пустой() Тогда
Выборка = РезультатЗапроса.Выбрать();
Выборка.Следующий();
Почта = Выборка.ПочтаРуководителя;
КонецЕсли;
Использование конструкции ЕСТЬNULL в запросе позволяет нам сразу определить, какое значение мы хотим получить, если данные отсутствуют, что полностью исключает ошибку «Значение не является значением объектного типа» в последующей обработке.
Подведем итоги нашего исследования проблемы:
НайтиПоНаименованию) перед тем, как обращаться к его свойствам.Родителя.ТипЗнч() для выявления реального типа переменной, вызывающей ошибку.ОбщегоНазначения.ЗначениеРеквизитаОбъекта() или прямым запросам к базе данных. Это сделает ваш код стабильным, быстрым и защищенным от неожиданных изменений в данных пользователей.