В чем разница между проверкой типа через ДокументОбъект.Ссылка и ДокументОбъект в 1С?

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

В процессе разработки в среде «1С:Предприятие» перед нами регулярно возникает задача определения типа данных конкретной переменной. Особенно часто это требуется при написании универсальных процедур, обработчиков подписок на события или при работе в модулях форм. На первый взгляд, две проверки:


Если ТипЗнч(ДокументОбъект.Ссылка) = Тип("ДокументСсылка.Тест1") Тогда
// ...
КонецЕсли;

и


Если ТипЗнч(ДокументОбъект) = Тип("ДокументОбъект.Тест1") Тогда
// ...
КонецЕсли;

кажутся эквивалентными, ведь обе они призваны идентифицировать принадлежность переменной к конкретному документу Тест1. Однако за этой внешней схожестью скрываются фундаментальные различия в архитектуре платформы «1С:Предприятие 8». Непонимание этих нюансов может приводить к трудноуловимым ошибкам времени выполнения, особенно в управляемом интерфейсе. Рассмотрим детально особенности каждого подхода.

1. Поведение свойства Ссылка для нового (не записанного) документа

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

Когда мы программно создаем новый документ в оперативной памяти (например, с помощью метода Документы.Тест1.СоздатьДокумент()), платформа «1С:Предприятие» выполняет следующие действия:

  1. В памяти выделяется адресное пространство под структуру нового объекта данных.
  2. Платформа **сразу же генерирует** для этого объекта новый уникальный идентификатор (UUID).
  3. Этот идентификатор связывается со свойством Ссылка создаваемого объекта.

Таким образом, даже если документ ни разу не записывался в базу данных и существует только в оперативной памяти, его свойство Ссылка уже инициализировано. Оно содержит полноценную ссылку типа ДокументСсылка.Тест1. Эта ссылка не является «пустой» (в терминах метода Пустая()), так как содержит сгенерированный UUID.

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

2. Контекст управляемых форм и тип ДанныеФормыСтруктура

Это самый критически важный аспект, который зачастую упускается при проектировании кода. В управляемом приложении мы повсеместно работаем с управляемыми формами. Переменная Объект (или любая другая переменная, связанная с основным реквизитом формы типа «Документ») на клиенте и в серверных обработчиках формы имеет совершенно иной тип данных.

Она принадлежит к типу ДанныеФормыСтруктура, а не к типу ДокументОбъект.Тест1. Платформа 1С использует этот специализированный тип для минимизации трафика между клиентом и сервером и оптимизации работы интерфейса.

Разберем, к чему это приводит при выполнении проверок:

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

Именно эта особенность делает проверку через свойство Ссылка гораздо более гибкой и жизнеспособной. Код становится универсальным и не ломается при переносе или вызове процедур из различных контекстов исполнения.

3. Написание универсального кода и свойство идемпотентности

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

Если использовать проверку типов напрямую через объект, нам придется писать громоздкие и нечитаемые конструкции, учитывающие оба варианта:


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

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

Благодаря этому свойству мы можем сократить проверку до одной лаконичной строки:


Если ТипЗнч(Параметр.Ссылка) = Тип("ДокументСсылка.Тест1") Тогда
   // Код сработает и для объекта, и для ссылки!
КонецЕсли;

Важное предостережение при использовании этого подхода:

Если в анализируемый Параметр может быть передано значение примитивного типа (число, строка, булево, дата) или коллекция (структура, массив, таблица значений), то попытка прямого обращения к свойству Параметр.Ссылка вызовет критическую ошибку выполнения платформы: «Поле объекта не обнаружено (Ссылка)».

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


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

4. Влияние на производительность системы

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

Спешим развеять эти опасения: это абсолютно не так. Объект типа ДокументОбъект уже содержит в своей структуре в оперативной памяти готовое значение ссылки (тот самый сгенерированный UUID). Платформе нет никакой необходимости обращаться к СУБД для получения этого значения. Операция выполняется мгновенно и не создает нагрузки на сервер базы данных.

Также важно отметить, что связка функций ТипЗнч() = Тип() является самым быстрым способом сравнения типов в экосистеме 1С на уровне ядра платформы. Некоторые разработчики пытаются определять тип через метаданные, например:

Если Параметр.Метаданные().Имя = "Тест1" Тогда ...

Такой подход работает **значительно медленнее**, поскольку обращение к метаданным объекта является ресурсоемкой операцией («тяжелый» системный вызов). Использование прямого сравнения типов через ТипЗнч всегда предпочтительнее с точки зрения быстродействия.

Резюме: какой вариант использовать на практике?

Для того чтобы ваш код был качественным, быстрым и не приводил к ошибкам, рекомендуем придерживаться следующих правил:

← На главную