Разработка и Конфигурация · 10 мин
Как проверить, есть ли свойство у объекта в 1С
Как проверить, есть ли свойство (реквизит) у объекта в 1С: через метаданные, ЕстьРеквизитОбъекта, Попытка и Структуру. Примеры кода, ошибки и советы разработчику.
При разработке на встроенном языке 1С регулярно возникает задача: перед обращением к реквизиту или свойству объекта убедиться, что оно вообще существует. Это особенно актуально в универсальных обработках, обменах данными и расширениях, где состав реквизитов объекта может отличаться в зависимости от конфигурации, версии или настроек.
Прямого метода вида «ЕстьСвойство» у большинства объектов 1С нет, поэтому разработчики используют несколько обходных приёмов: проверку через метаданные, обращение через Попытку/Исключение, анализ структур и специальные функции из типовых библиотек. У каждого подхода есть свои условия применения, ограничения и подводные камни.
Ниже разобраны основные способы проверки с примерами кода, указано, когда какой вариант выбирать, и собраны типичные ошибки, которые приводят к падению кода или ложным результатам.
Почему нельзя просто обратиться к свойству
Если обратиться к несуществующему реквизиту объекта, например Док.НесуществующийРеквизит, выполнение кода прервётся с ошибкой «Поле объекта не обнаружено». В отлаженном коде, где состав реквизитов известен, это не проблема, но в универсальных механизмах такое обращение недопустимо.
Типичные ситуации, когда проверка обязательна:
- обработка объектов разных видов в цикле (документы разных типов с неодинаковым набором реквизитов);
- обмены данными, где соответствие полей не гарантировано;
- расширения конфигурации, где реквизит мог быть добавлен или удалён;
- работа со структурами и соответствиями, собранными динамически;
- совместимость кода с разными версиями конфигурации.
Выбор способа проверки зависит от типа объекта: прикладной объект конфигурации, структура, строка таблицы значений или произвольное значение, полученное извне.
Проверка реквизита через метаданные
Самый надёжный способ для прикладных объектов (справочников, документов, регистров) — обратиться к описанию объекта через метаданные. У каждого объекта есть метод Метаданные(), возвращающий его описание, а у него — коллекции реквизитов.
Функция ЕстьРеквизит(Объект, ИмяРеквизита)
МетаданныеОбъекта = Объект.Метаданные();
Возврат МетаданныеОбъекта.Реквизиты.Найти(ИмяРеквизита) <> Неопределено;
КонецФункции
Если метод Найти() вернул Неопределено, реквизита у объекта нет. Обратите внимание: коллекция Реквизиты содержит только реквизиты, добавленные в конфигураторе. Стандартные реквизиты (Ссылка, Номер, Дата, Проведен и т.п.) находятся в коллекции СтандартныеРеквизиты, а у документов есть ещё общие реквизиты и реквизиты табличных частей.
Для полной проверки часто пишут расширенный вариант, учитывающий стандартные реквизиты и табличные части. Именно так устроена функция ЕстьРеквизитОбъекта в Библиотеке стандартных подсистем (БСП).
Готовая функция из типовых конфигураций
В конфигурациях на базе БСП есть готовая функция общего модуля ОбщегоНазначения:
Если ОбщегоНазначения.ЕстьРеквизитОбъекта("Организация", ДокументОбъект.Метаданные()) Тогда
Организация = ДокументОбъект.Организация;
КонецЕсли;
Функция принимает имя реквизита и объект метаданных, а возвращает Истина или Ложь. Внутри она корректно обрабатывает стандартные реквизиты и особенности разных типов объектов, поэтому в типовой конфигурации лучше использовать её, а не писать собственный вариант.
Если вы разрабатываете расширение или внешнюю обработку, учтите: при вызове из внешнего кода убедитесь, что общий модуль доступен (флажок «Вызов сервера» / «Клиент (обычное приложение)» в зависимости от контекста). В собственных конфигурациях без БСП функцию придётся реализовать самостоятельно по примеру выше.
Проверка свойства у структуры
У объекта типа Структура есть штатный метод Свойство(), который одновременно проверяет наличие ключа и возвращает его значение:
Значение = Неопределено;
Если СтруктураПараметров.Свойство("Склад", Значение) Тогда
// ключ есть, значение в переменной Значение
Иначе
// ключа нет
КонецЕсли;
Метод возвращает Истина, если ключ найден, даже если значение ключа равно Неопределено. Это важное отличие от проверки вида Если Структура.Склад <> Неопределено, которая упадёт с ошибкой при отсутствии ключа.
Для соответствий аналогичную роль играет обращение по ключу: Соответствие[Ключ] возвращает Неопределено при отсутствии ключа без ошибки. Но здесь нельзя отличить «ключа нет» от «ключ есть, значение Неопределено» — если это критично, используйте структуру.
Как выбрать способ проверки
Проверка через Попытка/Исключение
Когда тип объекта неизвестен или нужно проверить программное свойство (не реквизит метаданных), применяют обращение внутри конструкции Попытка/Исключение:
Функция ЕстьСвойство(Объект, ИмяСвойства)
Попытка
Значение = Объект[ИмяСвойства];
Возврат Истина;
Исключение
Возврат Ложь;
КонецПопытки;
КонецФункции
Обращение через квадратные скобки Объект[ИмяСвойства] позволяет передать имя строкой. Если свойства нет, сработает исключение, и функция вернёт Ложь.
У этого способа два недостатка. Во-первых, он медленнее проверки через метаданные, особенно в циклах. Во-вторых, исключение может возникнуть не только из-за отсутствия свойства, но и из-за ошибки внутри обращения к значению — и вы получите ложный отрицательный результат. Поэтому Попытку стоит использовать только там, где метаданные недоступны или тип объекта произвольный.
Проверка колонок таблицы значений и реквизитов формы
Для таблиц значений проверка делается через коллекцию колонок:
Если ТаблицаДанных.Колонки.Найти("СуммаНДС") <> Неопределено Тогда
Итог = ТаблицаДанных.Итог("СуммаНДС");
КонецЕсли;
На управляемой форме реквизиты формы проверяются иначе: через метод ПолучитьРеквизиты() объекта УправляемаяФорма, который возвращает массив реквизитов, или через попытку обращения к ЭтаФорма[ИмяРеквизита]. Для динамически создаваемых реквизитов формы (метод ИзменитьРеквизиты) обычно ведут собственный список добавленных имён — это надёжнее, чем перебор.
Отдельный случай — данные, полученные из внешних источников: JSON, XML, веб-сервисы. После разбора через ПрочитатьJSON вы получаете структуру или соответствие, и проверка выполняется описанными выше методами до обращения к полям.
Проверка типа перед проверкой свойства
Перед любой проверкой убедитесь, что переменная вообще содержит объект нужного типа. Вызов Метаданные() у строки, числа или Неопределено приведёт к ошибке ещё до проверки реквизита:
Если Не ЗначениеЗаполнено(Парам) Тогда
Возврат Ложь;
КонецЕсли;
ТипПараметра = ТипЗнч(Парам);
Если ТипПараметра = Тип("Структура") Тогда
// проверка через Свойство()
ИначеЕсли Метаданные.НайтиПоТипу(ТипПараметра) <> Неопределено Тогда
// прикладной объект — проверка через метаданные
КонецЕсли;
Метод Метаданные.НайтиПоТипу() удобен, когда нужно понять, является ли значение объектом конфигурации вообще, не зная его конкретного вида. Это стандартный приём в универсальных процедурах сериализации и логирования.
- 1Определите тип значения через ТипЗнч() и отсеките Неопределено
- 2Для структуры используйте метод Свойство() с выходным параметром
- 3Для прикладного объекта проверьте реквизит через Метаданные().Реквизиты.Найти() или функцию БСП
- 4Учтите стандартные реквизиты и табличные части, если ищете их
- 5Только если тип неизвестен — оберните обращение в Попытка/Исключение
- 6Проверьте результат на тестовых данных с объектом, где свойство гарантированно отсутствует
Производительность и кэширование
Обращение к метаданным — относительно дорогая операция. Если проверка выполняется внутри цикла по тысячам объектов одного типа, вызывать Метаданные().Реквизиты.Найти() на каждой итерации расточительно. Правильный подход — получить объект метаданных один раз до цикла и проверять реквизит по нему, либо закэшировать результат проверки в соответствии по имени типа.
В серверных процедурах с массовой обработкой разница заметна на практике. Для клиентского кода кэширование тем более важно, так как обращение к метаданным на клиенте может потребовать серверного вызова в зависимости от контекста.
Что важно запомнить
Проверяйте реквизиты прикладных объектов через метаданные (или ЕстьРеквизитОбъекта из БСП), ключи структур — методом Свойство(), а Попытка/Исключение оставьте для случаев неизвестного типа. Перед проверкой убеждайтесь в типе значения через ТипЗнч() и не смешивайте отсутствие свойства с пустым значением.
Частые вопросы
Как проверить наличие табличной части у документа?
Через метаданные: Объект.Метаданные().ТабличныеЧасти.Найти("Товары"). Если метод вернул Неопределено — табличной части с таким именем у объекта нет. Реквизиты внутри табличной части проверяются через коллекцию Реквизиты найденного описания табличной части.
Чем отличается проверка свойства от проверки на Неопределено?
Проверка на Неопределено отвечает на вопрос «заполнено ли значение», а не «существует ли свойство». Свойство может существовать и быть пустым. Если обратиться к несуществующему свойству для сравнения с Неопределено, код упадёт с ошибкой, поэтому сначала проверяют существование, потом значение.
Работает ли ЕстьРеквизитОбъекта в расширении конфигурации?
Да, если в расширении доступен общий модуль ОбщегоНазначения основной конфигурации. Функция учитывает и реквизиты, добавленные расширением, поскольку читает актуальные метаданные объекта.
Можно ли проверить наличие метода у объекта?
Штатного способа нет. Обычно используют Попытка/Исключение с вызовом метода или проверяют тип объекта через ТипЗнч(), если набор методов известен заранее. Для экспортных процедур общих модулей проверяют само существование модуля через Вычислить() в безопасном режиме.
Как проверить свойство у объекта, полученного по COM-соединению?
Для COM-объектов методы метаданных и ТипЗнч() работают ограниченно. Практичный вариант — обращение через Попытка/Исключение на стороне вызывающей базы либо выполнение проверки через метаданные внутри подключённой базы с возвратом результата.