Как в 1С программно отличить ссылку от объекта?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В практике разработки на платформе 1С:Предприятие часто возникают ситуации, когда в универсальную функцию или процедуру передается параметр, содержащий данные документа, справочника или другого ссылочного типа. При этом заранее неизвестно, что именно пришло в функцию: ссылка (например, ДокументСсылка.РеализацияТоваровУслуг) или объект (ДокументОбъект.РеализацияТоваровУслуг). Это критически важно, так как методы работы с ними кардинально различаются: у объекта можно менять реквизиты и вызывать метод Записать(), а у ссылки — нет.

Разберем подробно все существующие способы идентификации, проанализируем их надежность и влияние на производительность системы.

Способ 1. Сравнение значения с его собственным свойством Ссылка

Это один из самых изящных и быстрых способов. Рассмотрим логику: у любого ссылочного типа (документа, справочника) есть свойство Ссылка. Для самой ссылки это свойство возвращает это же самое значение. Для объекта это свойство возвращает ссылку на этот объект в базе данных.

Проанализируем пример кода:


Если Источник.Ссылка = Источник Тогда
    // В переменной находится ссылка
Иначе
    // В переменной находится объект
КонецЕсли;

Почему это работает? Платформа 1С оптимизирована таким образом, что обращение к свойству Ссылка у самой ссылки не инициирует обращение к базе данных (SQL-запрос). Платформа понимает, что значение уже является ссылкой. Если же перед нами объект, то Источник.Ссылка вернет значение типа "Ссылка", которое по определению не равно типу "Объект".

Важный нюанс: если объект новый и еще ни разу не записывался в базу, Источник.Ссылка вернет пустую ссылку. Проверка все равно сработает корректно: пустая ссылка не равна объекту.

Способ 2. Сравнение типов через ТипЗнч

Этот метод считается более строгим и часто рекомендуется для использования в сложных алгоритмах. Мы сравниваем тип значения параметра с типом, который возвращает его свойство Ссылка.

Посмотрим на реализацию:


Если ТипЗнч(Параметр) = ТипЗнч(Параметр.Ссылка) Тогда
    // Это ссылка (типы совпадают)
Иначе
    // Это объект (тип объекта не равен типу ссылки)
КонецЕсли;

Данный подход хорош тем, что он исключает ошибки неявного приведения типов и работает максимально прозрачно для разработчика. Однако стоит помнить, что обращение через точку к свойству Ссылка у объекта, находящегося в памяти, безопасно, но злоупотреблять обращениями через точку к другим реквизитам не стоит из-за падения производительности.

Способ 3. Использование XMLТипЗнч (самый технологичный способ)

Существует продвинутый метод, основанный на механизме сериализации XDTO. Функция XMLТипЗнч возвращает описание типа в формате XML, которое жестко стандартизировано платформой 1С. Для ссылок и объектов имена типов всегда будут иметь специфические суффиксы.

Рассмотрим, как это выглядит в коде:


ИмяТипаXML = XMLТипЗнч(Данные).ИмяТипа;
Если СтрНайти(ИмяТипаXML, "Ref") > 0 Тогда
    // Это ссылка (например, DocumentRef.Реализация)
ИначеЕсли СтрНайти(ИмяТипаXML, "Object") > 0 Тогда
    // Это объект (например, DocumentObject.Реализация)
КонецЕсли;

Преимущество: Этот способ работает на уровне типов платформы и не требует даже потенциального обращения к данным объекта. Он крайне эффективен в высоконагруженных системах.

Способ 4. Использование менеджеров типов (ТипВсеСсылки)

Если нам нужно понять, является ли значение в принципе ссылочным типом (а не строкой или числом), мы можем использовать коллекции менеджеров. У каждого класса метаданных (Справочники, Документы, ПланыВидовХарактеристик) есть метод ТипВсеСсылки(), который возвращает ОписаниеТипов, содержащее все возможные ссылки данного класса.

Пример проверки для документов:


Если Документы.ТипВсеСсылки().СодержитТип(ТипЗнч(ПроверяемоеЗначение)) Тогда
    // Это точно ссылка на какой-то документ
КонецЕсли;

Чтобы сделать функцию абсолютно универсальной (для справочников и документов одновременно), можно объединить типы:


МассивТипов = Новый Массив;
МассивТипов.Добавить(Тип("СправочникСсылка.Номенклатура")); // Пример
// Но лучше использовать системные коллекции:
Если Справочники.ТипВсеСсылки().СодержитТип(ТипЗнч(Значение)) 
   ИЛИ Документы.ТипВсеСсылки().СодержитТип(ТипЗнч(Значение)) Тогда
    // Перед нами ссылка
КонецЕсли;

Способ 5. Использование стандартных подсистем (БСП)

Если ваша конфигурация построена на базе Библиотеки стандартных подсистем (БСП), вам не нужно изобретать велосипед. В общем модуле ОбщегоНазначения уже реализована проверенная и максимально оптимизированная функция.

Проанализируем вызов:


// Возвращает Истина, если переданное значение - ссылка
Результат = ОбщегоНазначения.ЭтоСсылка(ТипЗнч(ВашеЗначение));

Внутри БСП этот метод обычно реализован через проверку вхождения типа в предопределенный массив всех ссылочных типов конфигурации, что обеспечивает наивысшую скорость работы.

Важные замечания по производительности и контексту

Выясним причину, по которой следует избегать проверки через ТипЗнчСтр() и поиск подстроки "ДокументОбъект". Как правильно заметили участники обсуждения, имя документа может содержать такие слова (например, документ с именем "УдалениеДокументОбъектов"), что приведет к ложному срабатыванию.

Проанализируем контекст выполнения:

  1. Тонкий клиент: На тонком клиенте типы "Объект" (например, ДокументОбъект) физически не могут существовать. Если ваш код выполняется "НаКлиенте", то любая переменная с данными документа — это либо Ссылка, либо ДанныеФормыСтруктура. Проверять на "Объект" здесь не имеет смысла.
  2. Мутабельные значения: Помните, что передача объектов с сервера на клиент невозможна и вызывает ошибку. Поэтому, если вы пишете универсальную процедуру, которая может вызываться из разных контекстов, всегда отдавайте предпочтение работе со ссылками.
  3. Метаданные: Самый надежный способ узнать всё о типе — это обратиться к метаданным: Метаданные.НайтиПоТипу(ТипЗнч(Значение)). У полученного объекта метаданных можно проверить свойства ТипСсылки и ТипОбъекта, сравнив их с типом вашего значения.

Подводя итог, для повседневных задач наиболее рекомендуемым является Способ 1 (сравнение свойства .Ссылка) из-за его простоты и отсутствия лишних затрат ресурсов. Для тиражируемых решений лучше использовать Способ 5 (функции БСП), так как они учитывают все нюансы платформы, включая расширения и специфические типы данных.

← На главную