В процессе разработки универсальных механизмов, обработок загрузки данных или алгоритмов проведения часто возникает задача определить тип переданной переменной. Если в процедуру может поступить значение произвольного типа (число, строка, структура, ссылка или пустая переменная), прямое обращение к свойствам объекта может вызвать синтаксическую или исключительную ошибку. Разберем по шагам, как корректно и производительно определить ссылочность значения встроенными средствами платформы 1С:Предприятие 8.
Каждая коллекция менеджеров ссылочных объектов метаданных (Справочники, Документы, ПланыВидовХарактеристик и другие) предоставляет метод ТипВсеСсылки(). Данный метод возвращает объект ОписаниеТипов, содержащий все ссылочные типы конфигурации для соответствующего класса метаданных.
Проанализируем важный нюанс платформы: если в конфигурации создано более одного объекта метаданных указанного вида, метод ТипВсеСсылки() возвращает составное описание типов. Любое составное ОписаниеТипов в платформе 1С неявно включает в себя тип Неопределено (как значение по умолчанию). По этой причине метод СодержитТип(Тип("Неопределено")) вернет Истина, что может привести к ложному срабатыванию проверки. Поэтому перед проверкой типа обязательно отсекаем Неопределено.
Посмотрим на пример универсальной проверки значения на принадлежность к справочникам или документам:
Функция ЭтоСсылкаНаСправочникИлиДокумент(Значение) Экспорт
Если Значение = Неопределено Тогда
Возврат Ложь;
КонецЕсли;
ТипЗначения = ТипЗнч(Значение);
Если Справочники.ТипВсеСсылки().СодержитТип(ТипЗначения)
Или Документы.ТипВсеСсылки().СодержитТип(ТипЗначения) Тогда
Возврат Истина;
КонецЕсли;
Возврат Ложь;
КонецФункции
Обратите внимание на синтаксис: метод объекта ОписаниеТипов называется именно СодержитТип(), а аргументом в него передается ТипЗнч(Значение).
Если разработка ведется в типовой или доработанной конфигурации, содержащей Библиотеку стандартных подсистем, нет необходимости создавать собственные функции обхода типов. В БСП предусмотрены оптимизированные методы, доступные в общем модуле ОбщегоНазначенияКлиентСервер.
Рассмотрим вызов стандартной функции:
Если ОбщегоНазначенияКлиентСервер.ЭтоСсылка(ПроверяемоеЗначение) Тогда
// Выполняем действия со ссылочным объектом
КонецЕсли;
Преимущество этого подхода заключается в том, что функция ЭтоСсылка() корректно обрабатывает все ссылочные типы (включая перечисления, планы счетов, планы обмена, бизнес-процессы и задачи), проверяет входное значение на Неопределено и доступна в общем контексте тонкого клиента и сервера.
Существует еще один быстрый и универсальный способ проверить, является ли значение ссылкой любого вида, не перечисляя коллекции менеджеров. Для этого можно воспользоваться платформенной функцией XMLТип().
Разберем механизм: для ссылочных данных сериализатор платформы формирует XML-тип с суффиксом Ref (например, CatalogRef.Номенклатура или DocumentRef.РеализацияТоваровУслуг). Если значение не относится к ссылочным типам, суффикс будет отсутствовать либо функция вернет Неопределено.
Посмотрим на реализацию проверки:
Функция ЭтоЛюбаяСсылка(Значение) Экспорт
ТипXML = XMLТип(ТипЗнч(Значение));
Если ТипXML = Неопределено Тогда
Возврат Ложь;
КонецЕсли;
Возврат Прав(ТипXML.ИмяТипа, 3) = "Ref";
КонецФункции
В процессе обсуждения часто предлагаются альтернативные варианты, которые приводят к скрытым ошибкам или падению производительности. Выясним их причины:
Значение.Ссылка = Значение крайне неэффективна. При обращении через точку к свойству объектной сущности или битой ссылке платформа может инициировать неявный запрос к базе данных для считывания полей, что создает неоправданную нагрузку на СУБД.Значение.Метаданные() вызовет фатальную ошибку времени выполнения, если в переменную передано примитивное значение (число, строка, дата), Неопределено или системная коллекция (структура, массив, таблица значений).СправочникСсылка), но и для объектных типов (СправочникОбъект), а также для выборок. Это не позволяет разграничить ссылку в базе данных и объект, находящийся в оперативной памяти.Справочники.ТипВсеСсылки() и обращение к объекту Метаданные доступны только на стороне сервера, во внешнем соединении или в толстом клиенте. Для тонкого клиента следует применять клиентские функции БСП либо передавать проверку на сервер.