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