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