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