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