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