Как проверить наличие реквизита в 1С без использования конструкции Попытка...Исключение

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В процессе разработки на платформе 1С:Предприятие 8 часто возникает необходимость проверить, обладает ли объект (справочник, документ или структура) определенным реквизитом. Традиционный подход с использованием блока Попытка...Исключение считается "ленивым" и иногда нежелательным, так как он может замедлять работу системы (особенно в циклах) и замусоривать технологический журнал ошибками. В данной статье мы подробно разберем несколько альтернативных и более изящных способов решения этой задачи.

Метод 1: Использование коллекции Метаданные

Самый правильный с точки зрения архитектуры платформы способ — это обращение к описанию объекта. У каждого объекта конфигурации есть программный доступ к его структуре через свойство Метаданные(). Рассмотрим, как это реализовать одной строкой кода.

Проанализируем пример функции, которая проверяет наличие обычного реквизита:


Функция ЕстьРеквизитОбъекта(Объект, ИмяРеквизита) Экспорт
    МетаданныеОбъекта = Объект.Метаданные();
    Возврат НЕ (МетаданныеОбъекта.Реквизиты.Найти(ИмяРеквизита) = Неопределено);
КонецФункции

Однако здесь есть важный нюанс: коллекции метаданных разделены. Реквизиты, которые добавил разработчик, находятся в коллекции Реквизиты, но системные поля (такие как Код, Наименование, Дата, Номер) находятся в коллекции СтандартныеРеквизиты. Если мы хотим универсальную проверку, нам нужно проверить обе коллекции.

Разберем улучшенную проверку:


Функция ЕстьЛюбойРеквизит(Объект, ИмяРеквизита) Экспорт
    МД = Объект.Метаданные();
    
    // Проверяем обычные реквизиты
    Если МД.Реквизиты.Найти(ИмяРеквизита) <> Неопределено Тогда
        Возврат Истина;
    КонецЕсли;
    
    // Проверяем стандартные реквизиты
    Для Каждого СтандартныйРеквизит Из МД.СтандартныеРеквизиты Цикл
        Если СтандартныйРеквизит.Имя = ИмяРеквизита Тогда
            Возврат Истина;
        КонецЕсли;
    КонецЦикла;
    
    Возврат Ложь;
КонецФункции

Метод 2: Хитрость с функцией ЗаполнитьЗначенияСвойств

Существует очень интересный и быстрый "лайфхак", который часто используют опытные разработчики. Он основан на поведении платформенного метода ЗаполнитьЗначенияСвойств. Этот метод копирует значения из свойств одного объекта в другой по совпадающим именам, при этом не вызывая исключений, если реквизита не существует.

Выясним алгоритм этого метода:

  1. Создаем временную структуру с одним ключом, имя которого совпадает с искомым реквизитом.
  2. В качестве значения ключа записываем уникальный маркер (например, УникальныйИдентификатор).
  3. Пытаемся заполнить эту структуру из нашего объекта.
  4. Если значение в структуре изменилось — значит, реквизит у объекта существует и значение было скопировано.

Посмотрим на пример кода:


Функция ЕстьРеквизитЧерезЗаполнение(ПроверяемыйОбъект, ИмяРеквизита) Экспорт
    УИ = Новый УникальныйИдентификатор();
    СтруктураДляПроверки = Новый Структура(ИмяРеквизита, УИ);
    
    // Метод не выдаст ошибку, даже если у объекта нет такого реквизита
    ЗаполнитьЗначенияСвойств(СтруктураДляПроверки, ПроверяемыйОбъект);
    
    // Если значение в структуре больше не равно нашему УИ, значит реквизит найден
    Возврат СтруктураДляПроверки[ИмяРеквизита] <> УИ;
КонецФункции

Важный момент: этот способ работает быстрее, чем полный перебор метаданных, и он одинаково хорошо видит и обычные, и стандартные реквизиты. Однако стоит помнить, что он вызывает обращение к данным объекта, что может привести к подгрузке объекта из базы данных, если у вас на руках была только ссылка.

Метод 3: Использование встроенных функций БСП

Если ваша конфигурация разработана на базе Библиотеки Стандартных Подсистем (БСП), то вам не нужно изобретать велосипед. В общем модуле ОбщегоНазначения уже реализованы все необходимые проверки, учитывающие оптимизацию и кэширование.

Рассмотрим вызов стандартного метода:

ЕстьРеквизит = ОбщегоНазначения.ЕстьРеквизитОбъекта(Объект, "КонтактноеЛицо");

Этот метод внутри себя проверяет метаданные и корректно обрабатывает различные типы объектов (справочники, документы, бизнес-процессы и т.д.). Использование функций БСП — это "золотой стандарт" современной разработки в экосистеме 1С.

Метод 4: Проверка свойств управляемой формы

Когда мы работаем в контексте управляемой формы, объект Объект (тип ДанныеФормыСтруктура) ведет себя иначе, чем серверный объект. Для него доступен прямой метод Свойство(), аналогичный работе со структурой.

Проанализируем ситуацию на клиенте или в контексте формы:


Если Объект.Свойство("КонтактноеЛицо") Тогда
    // Делаем что-то с реквизитом
КонецЕсли;

Этот метод является максимально производительным, но он применим только к типам Структура, Соответствие или ДанныеФормыСтруктура. Попытка вызвать его у обычного СправочникОбъект приведет к ошибке компиляции.

Сравнение производительности

Многие задаются вопросом: "А стоит ли вообще уходить от Попытки?". Разберем результаты тестов производительности:

Выводы и рекомендации

Подведем итоги нашего исследования. Выбор метода зависит от контекста задачи:

  1. Если используется БСП — всегда используйте ОбщегоНазначения.ЕстьРеквизитОбъекта().
  2. Если нужно проверить структуру или данные формы — используйте метод Свойство().
  3. Для универсальных алгоритмов в самописных конфигурациях лучше всего подходит метод с ЗаполнитьЗначенияСвойств или детальный разбор Метаданные().

Исключение Попытка из кода делает ваши модули более профессиональными, надежными и предсказуемыми в плане производительности. Мы рекомендуем один раз вынести выбранный алгоритм в общий модуль вашей конфигурации и использовать его повсеместно.

← На главную