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