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