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