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