В практике разработки на платформе 1С часто возникают задачи, когда необходимо обработать параметры запроса или данные обмена динамически. Особенно это актуально, когда типы данных заранее не определены жестко, а формируются на лету из строковых представлений. В данной статье мы разберем, как корректно организовать поиск по «теневым» или динамическим объектам, переключаясь между справочниками и перечислениями.
Рассмотрим ситуацию: у нас есть список параметров, где тип объекта зашит в строку (например, через префикс теневая). Нам нужно получить ссылку на объект. Если это справочник, мы ищем по наименованию. Если это перечисление — по внутреннему имени (идентификатору) значения. Основная сложность заключается в том, что прямое обращение к коллекции Перечисления по несуществующему имени приведет к аварийному завершению работы программы.
Проанализируем базовый алгоритм, который поможет нам безопасно определять тип объекта и извлекать данные.
Самый надежный способ проверить, к какой категории относится объект (справочник или перечисление) — это обратиться к коллекции Метаданные (или использовать информер по метаданным). Разберем по шагам, как это реализовать в коде.
// Формируем имя объекта для поиска в метаданных
имяОбъекта = "теневая" + НРег(СтрЗаменить(Параметр.ТипПараметра, " ", ""));
// 1. Проверяем, существует ли такой справочник
Если НЕ Метаданные.Справочники.Найти(имяОбъекта) = Неопределено Тогда
// Если справочник найден, используем стандартный метод поиска по наименованию
ЗначениеПараметра = Справочники[имяОбъекта].НайтиПоНаименованию(Параметр.ЗначениеПараметра, Истина);
// 2. Если справочник не найден, проверяем коллекцию перечислений
ИначеЕсли НЕ Метаданные.Перечисления.Найти(имяОбъекта) = Неопределено Тогда
// Внутри перечисления нужно также проверить наличие конкретного значения по имени
ОбъектМетаданныхПеречисление = Метаданные.Перечисления.Найти(имяОбъекта);
Если НЕ ОбъектМетаданныхПеречисление.ЗначенияПеречисления.Найти(Параметр.ЗначениеПараметра) = Неопределено Тогда
// Если значение существует, получаем ссылку через менеджер перечисления
ЗначениеПараметра = Перечисления[имяОбъекта][Параметр.ЗначениеПараметра];
Иначе
ЗначениеПараметра = Неопределено;
КонецЕсли;
КонецЕсли;
В данном примере мы используем метод Найти() для коллекций метаданных. Это позволяет избежать исключений. Важно отметить использование второго параметра Истина в методе НайтиПоНаименованию() для справочников — это гарантирует точное соответствие строки, что критично при автоматической установке параметров запроса.
Вместо перебора коллекций метаданных, мы можем воспользоваться системной функцией Тип(). Если сконструированная строка типа верна, функция вернет объект типа Тип, в противном случае — Неопределено. Посмотрим, как это выглядит на практике:
имяОбъекта = "теневая" + НРег(СтрЗаменить(Параметр.ТипПараметра, " ", ""));
// Пытаемся определить, справочник это или перечисление через системные типы
ТипСправочника = Тип("СправочникСсылка." + имяОбъекта);
ТипПеречисления = Тип("ПеречислениеСсылка." + имяОбъекта);
Если ТипСправочника <> Тип("Неопределено") Тогда
ЗначениеПараметра = Справочники[имяОбъекта].НайтиПоНаименованию(Параметр.ЗначениеПараметра, Истина);
ИначеЕсли ТипПеречисления <> Тип("Неопределено") Тогда
Попытка
ЗначениеПараметра = Перечисления[имяОбъекта][Параметр.ЗначениеПараметра];
Исключение
ЗначениеПараметра = Неопределено; // Значение в перечислении не найдено
КонецПопытки;
КонецЕсли;
Этот метод считается более элегантным и коротким. Однако стоит помнить, что конструкция Попытка...Исключение внутри цикла может незначительно снизить производительность, если исключения будут возникать слишком часто.
Проанализируем важные технические моменты, которые часто упускают разработчики, выполняя поиск ссылок на справочник, перечисление или другие объекты:
Перечисления[имяОбъекта][ИмяЗначения] работает только с Именем (идентификатором), заданным в конфигураторе. Если в параметре ЗначениеПараметра передается пользовательский синоним (например, "НДС 20%" вместо "НДС20"), такой поиск вернет ошибку или Неопределено. Для поиска по синониму придется перебирать все значения перечисления в цикле и сравнивать их строковое представление.НайтиПоНаименованию без указания второго параметра выполняет поиск по началу строки. Если вы ищете товар "Гвоздь", а в базе есть "Гвоздь стальной", система может вернуть не то, что вы ожидали. Всегда используйте точный поиск, при необходимости задействуя получение даты создания объекта для верификации.Метаданные.Справочники.Найти() может замедлить работу. В этом случае рекомендуем один раз перед циклом создать Соответствие, в которое поместить имена всех нужных объектов, и проверять наличие имени уже в этом «кэше» в оперативной памяти.Выясним причину, почему иногда выгодно использовать сериализацию. Существует «хитрый» способ получить ссылку на любое перечисление или справочник, если у нас есть строковое имя типа и строковый идентификатор. Это делается через механизмы XML или JSON преобразования.
// Пример логики для перечисления через XMLТип (схематично)
СтрокаXML = "<Value>EnumRef." + имяОбъекта + "." + Параметр.ЗначениеПараметра + "</Value>";
// Далее используется десериализация через СредстваXML или аналогичные механизмы.
Хотя этот метод технически сложнее в реализации и «тяжелее» для процессора, он позволяет написать универсальный код, который не содержит условий Если Справочник ... ИначеЕсли Перечисление.
Мы рассмотрели несколько подходов к решению задачи динамического поиска. Проанализировав ситуацию, можно сделать вывод: наиболее сбалансированным решением является проверка через метаданные (Решение 1). Она обеспечивает максимальную безопасность кода и наглядность для других разработчиков, которые будут поддерживать вашу систему. Не забывайте про разницу между именами и синонимами, а также всегда учитывайте возможность дублирования имен в разных коллекциях метаданных.