В процессе разработки на платформе 1С:Предприятие часто возникает задача создания универсальных алгоритмов. Например, когда функция получает на вход некое Значение, и нам нужно понять: это ссылка на справочник, документ, или, возможно, сам объект (в оперативной памяти), либо вовсе отчет или обработка. Сложность заключается в том, что обычная функция ТипЗнч() возвращает конкретный тип (например, СправочникСсылка.Номенклатура), а нам нужно определить его принадлежность к «классу» (метаданным) объектов.
Разберем подробно все способы решения этой задачи, от простых проверок до универсальных методов, работающих как со ссылками, так и с объектами.
Проанализируем наиболее надежный и универсальный подход. Он хорош тем, что корректно обрабатывает и ссылки (CatalogRef), и объекты (CatalogObject). Суть метода заключается в получении описания объекта метаданных по типу переданного значения.
Рассмотрим пример реализации:
// Переменная Значение может содержать ссылку или объект
МетаОбъекта = Метаданные.НайтиПоТипу(ТипЗнч(Значение));
Если МетаОбъекта <> Неопределено Тогда
Если Метаданные.Документы.Содержит(МетаОбъекта) Тогда
Сообщить("Это документ: " + МетаОбъекта.Имя);
ИначеЕсли Метаданные.Справочники.Содержит(МетаОбъекта) Тогда
Сообщить("Это справочник: " + МетаОбъекта.Имя);
ИначеЕсли Метаданные.Отчеты.Содержит(МетаОбъекта) Тогда
Сообщить("Это отчет: " + МетаОбъекта.Имя);
Иначе
Сообщить("Это тип: " + МетаОбъекта.ПолноеИмя());
КонецЕсли;
КонецЕсли;
Почему это лучший вариант? Метод Метаданные.НайтиПоТипу() возвращает объект типа ОбъектМетаданных. После этого мы просто проверяем, входит ли этот объект в соответствующую коллекцию (Документы, Справочники и т.д.) с помощью метода Содержит(). Это работает стабильно и не зависит от языка интерфейса платформы.
Если мы заранее уверены, что работаем только со ссылками, можно воспользоваться глобальным контекстом и коллекциями менеджеров. У каждой коллекции (Справочники, Документы и т.д.) есть метод ТипВсеСсылки(), который возвращает описание типов всех объектов данного вида.
Посмотрим на код проверки:
ТипПроверяемогоЗначения = ТипЗнч(Значение);
Если Справочники.ТипВсеСсылки().СодержитТип(ТипПроверяемогоЗначения) Тогда
Сообщить("Это ссылка на справочник");
ИначеЕсли Документы.ТипВсеСсылки().СодержитТип(ТипПроверяемогоЗначения) Тогда
Сообщить("Это ссылка на документ");
КонецЕсли;
Важно помнить: этот способ не сработает для объектов (например, для СправочникОбъект), так как тип объекта не входит в состав ТипВсеСсылки. Если в ваш алгоритм может попасть объект, используйте первый способ.
Еще один эффективный метод — анализ строки ПолноеИмя(). Получив объект метаданных, мы можем быстро определить его категорию, проверив начало строки. Рассмотрим, как это реализовать:
ОбъектМетаданных = Метаданные.НайтиПоТипу(ТипЗнч(Значение));
Если ОбъектМетаданных <> Неопределено Тогда
ПолноеИмя = ОбъектМетаданных.ПолноеИмя(); // Вернет, например, "Справочник.Контрагенты"
Если СтрНачинаетсяС(ПолноеИмя, "Справочник") Тогда
Сообщить("Работаем со справочником");
ИначеЕсли СтрНачинаетсяС(ПолноеИмя, "Документ") Тогда
Сообщить("Работаем с документом");
КонецЕсли;
КонецЕсли;
Этот метод избавляет от необходимости перечислять все коллекции через ИначеЕсли, если вам нужно просто получить строковый префикс типа.
Если ваша конфигурация разработана на основе БСП, крайне рекомендуется использовать готовые функции из модуля ОбщегоНазначения. Это делает код более читаемым и соответствующим стандартам разработки фирмы «1С».
Проанализируем полезные функции БСП:
Справочники.Номенклатура), через который можно программно выполнять действия с объектом.Существует «хитрый» способ через сериализацию типа в XML. Он возвращает внутреннее имя типа платформы, которое не зависит от локализации (всегда на английском или всегда по стандарту XML).
ИмяТипаXML = XMLТип(ТипЗнч(Значение)).ИмяТипа;
Если Найти(ИмяТипаXML, "Catalog") > 0 Тогда
Сообщить("Это справочник (в терминах XML)");
КонецЕсли;
Метод специфичен и чаще используется в механизмах обмена данными, но его полезно знать как альтернативу, когда стандартные средства метаданных по какой-то причине недоступны (хотя в 1С 8.x такое бывает редко).
При выборе способа проверки учитывайте следующие моменты:
Метаданные.НайтиПоТипу() достаточно быстрое, но если вы делаете это в цикле на 100 000 итераций, лучше один раз кэшировать типы в соответствие или массив.Значение.Метаданные() напрямую (без НайтиПоТипу), программа может вызвать ошибку, если у значения нет этого метода (например, у Числа или Строки). Всегда проверяйте тип или используйте Попытку.ПланыВидовХарактеристик, Задачи, БизнесПроцессы и ПланыОбмена. Если вы пишете по-настоящему универсальный механизм (например, логирование изменений), ваш код должен уметь обрабатывать и их.Подводя итог, можно сказать, что для большинства повседневных задач программиста 1С оптимальным является Способ №1 (через Метаданные.НайтиПоТипу), так как он наиболее полно и безопасно отвечает на вопрос о принадлежности значения к объектам конфигурации.