К статье
Практический материал

Разработка и Конфигурация · 11 мин

Как по ссылке определить тип объекта в 1С

Как определить тип объекта по ссылке в 1С: функции ТипЗнч, метаданные, XMLТипЗнч, работа с составными типами. Примеры кода на встроенном языке и типичные ошибки.

Во встроенном языке 1С ссылка — это значение, которое указывает на конкретный объект базы данных: элемент справочника, документ, план счетов и так далее. Часто разработчик получает ссылку из реквизита составного типа, из запроса или из параметра процедуры и не знает заранее, какой именно вид объекта за ней скрывается. Задача определить тип по ссылке возникает при универсальных обработках, печати, обменах данными и формировании отчётов.

В платформе есть несколько штатных механизмов для этого: функция ТипЗнч, метод Метаданные() у ссылки, функции XMLТипЗнч и XMLТип, а также объектное описание типов. Каждый способ решает свою задачу: где-то нужно сравнить тип с эталоном, где-то — получить имя вида объекта строкой, а где-то — передать тип через сериализацию.

Ниже разобраны рабочие приёмы с примерами кода, ограничения каждого подхода и типичные ошибки, которые приводят к неверным ветвлениям логики или падению кода на неопределённых значениях.

Функция ТипЗнч — базовый способ определения типа

Функция ТипЗнч принимает любое значение и возвращает объект типа «Тип», описывающий его. Для ссылки на элемент справочника «Номенклатура» результатом будет тип «СправочникСсылка.Номенклатура», для документа — «ДокументСсылка.РеализацияТоваровУслуг» и так далее.

ТипСсылки = ТипЗнч(Ссылка);

Если ТипСсылки = Тип("СправочникСсылка.Номенклатура") Тогда

// обработка номенклатуры

ИначеЕсли ТипСсылки = Тип("ДокументСсылка.РеализацияТоваровУслуг") Тогда

// обработка документа

КонецЕсли;

Обратите внимание: функция Тип() принимает строковое имя типа и возвращает объект типа, с которым можно сравнивать результат ТипЗнч. Сравнение идёт строго по равенству — «СправочникСсылка.Номенклатура» и «СправочникОбъект.Номенклатура» это разные типы, хотя относятся к одному объекту метаданных.

Если тип указанного в строке метаданного не существует в конфигурации (например, справочник переименовали), вызов Тип() вернёт Неопределено. Поэтому при работе с именами, полученными извне, полезно проверять результат на Неопределено перед сравнением.

Получение имени вида объекта через Метаданные()

У любой ссылки есть метод Метаданные(), который возвращает объект описания метаданных. Через него доступны имя объекта, синоним, полное имя и принадлежность к классу метаданных. Это удобно, когда тип нужно показать пользователю, записать в журнал или сравнить с настройкой, хранящейся строкой.

Мета = Ссылка.Метаданные();

ИмяОбъекта = Мета.Имя; // "Номенклатура"

ПолноеИмя = Мета.ПолноеИмя(); // "Справочник.Номенклатура"

Представление = Мета.Представление(); // синоним для пользователя

Обратное преобразование тоже возможно: Метаданные.НайтиПоПолномуИмени("Справочник.Номенклатура") вернёт объект метаданных, а Метаданные.НайтиПоТипу(ТипЗнч(Ссылка)) — метаданные по типу. Метод НайтиПоТипу возвращает Неопределено, если тип не прикладной (например, число или строка), поэтому результат всегда проверяйте.

Метод Метаданные() безопасен для пустых ссылок: у пустой ссылки тип и метаданные определены, ошибки не будет. А вот у значения Неопределено метода Метаданные() нет — вызов приведёт к исключению.

Проверка принадлежности к классу: справочник, документ, перечисление

Часто нужен не конкретный вид объекта, а класс: любой справочник, любой документ, любой план видов характеристик. Для этого есть два рабочих подхода.

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

Функция ВидСсылки(Ссылка)

Мета = Ссылка.Метаданные();

Если Метаданные.Справочники.Содержит(Мета) Тогда

Возврат "Справочник";

ИначеЕсли Метаданные.Документы.Содержит(Мета) Тогда

Возврат "Документ";

ИначеЕсли Метаданные.Перечисления.Содержит(Мета) Тогда

Возврат "Перечисление";

Иначе

Возврат "Прочее";

КонецЕсли;

КонецФункции

Учтите, что перечисления — особый случай: значение перечисления формально не является ссылкой в полном смысле, но тип у него есть («ПеречислениеСсылка.Имя»), и Метаданные() у него работает. А вот у записей регистров сведений ссылки как таковой нет — там оперируют ключами записей, и тип определяется иначе.

Маршрут решения

Как выбрать способ

Нужно сравнить с конкретным видом объекта в кодеИспользуйте ТипЗнч(Ссылка) = Тип("СправочникСсылка.Имя")
Нужно имя вида строкой для журнала, настройки или сообщенияИспользуйте Ссылка.Метаданные().ПолноеИмя()
Нужно проверить принадлежность к классу (любой документ, любой справочник)Проверяйте через Метаданные.Документы.Содержит(Мета) и аналоги
Тип передаётся между системами или хранится в сериализованном видеИспользуйте XMLТипЗнч и XMLСтрока

XMLТипЗнч и сериализация типа

Когда тип нужно передать через веб-сервис, сохранить в хранилище значения или сопоставить при обмене, объект «Тип» преобразуют в XML-описание. Функция XMLТипЗнч(Значение) возвращает структуру с URI пространства имён и именем типа, а XMLСтрока и XMLЗначение позволяют сериализовать сам тип.

ОписаниеТипа = XMLТипЗнч(Ссылка);

// ОписаниеТипа.ИмяТипа — например "CatalogRef.Номенклатура"

// ОписаниеТипа.URIПространстваИмен — пространство имён типов

СтрокаТипа = XMLСтрока(ТипЗнч(Ссылка));

ВосстановленныйТип = XMLЗначение(Тип("Тип"), СтрокаТипа);

Этот механизм активно используется в универсальных обменах (EnterpriseData, XDTO-пакеты) и в планах обмена. Важное ограничение: восстановление типа из строки сработает только если в текущей конфигурации существует соответствующий объект метаданных. При обмене между разными конфигурациями имена могут не совпадать, и тогда нужна таблица соответствий.

Определение типа значения из запроса и составных реквизитов

При работе с запросами тип ссылки часто определяют прямо в тексте запроса. Функция ТИПЗНАЧЕНИЯ(Поле) возвращает тип, а оператор ССЫЛКА позволяет проверить принадлежность к конкретному виду. Конструкция ВЫБОР КОГДА ... ТОГДА помогает развести разные виды объектов по веткам обработки.

ВЫБОР

КОГДА ТИПЗНАЧЕНИЯ(Таблица.Контрагент) = ТИП(Справочник.Контрагенты)

ТОГДА "Контрагент"

КОГДА Таблица.Контрагент ССЫЛКА Справочник.ФизическиеЛица

ТОГДА "Физлицо"

ИНАЧЕ "Неопределено"

КОНЕЦ КАК ВидКонтрагента

В языке запросов функция ТИП() принимает имя без слова «Ссылка»: пишется ТИП(Справочник.Контрагенты), а не ТИП(СправочникСсылка.Контрагенты). Это частая ошибка при переносе логики из встроенного языка в запрос.

Для реквизитов составного типа полезно заранее посмотреть в конфигураторе, какие типы входят в состав: это снимает необходимость обрабатывать все мыслимые варианты. Если реквизит имеет тип «ЛюбаяСсылка», ветку «ИНАЧЕ» в логике делать обязательно — иначе при появлении нового вида объекта код молча отработает неправильно.

Типичные ошибки
01
Сравнение ТипЗнч(Ссылка) со строкой "СправочникСсылка.Номенклатура" — строка и объект типа не равны, условие никогда не сработает; сравнивать нужно с Тип(...).
02
Вызов Ссылка.Метаданные() у значения Неопределено или у примитивного типа — приводит к исключению; сначала проверяйте, что значение вообще ссылка.
03
Путаница между Ссылка и Объект: у объекта (СправочникОбъект) тип другой, и сравнение с типом ссылки даёт ложь.
04
Использование Тип("СправочникСсылка.Имя") для несуществующего объекта без проверки на Неопределено — сравнение молча не сработает.
05
Определение типа через строковое представление ссылки — представление зависит от локали и настроек и не предназначено для логики.

Практический порядок действий и проверка результата

Когда задача сформулирована как «есть ссылка неизвестного вида, нужно понять, что это», удобно действовать по фиксированной последовательности. Она защищает от исключений и даёт предсказуемый результат на любых входных данных.

Порядок действий
  1. 1
    Проверьте, что значение не равно Неопределено: иначе методы ссылки вызовут исключение.
  2. 2
    Убедитесь, что значение вообще ссылочного типа — через Метаданные.НайтиПоТипу(ТипЗнч(Значение)) <> Неопределено.
  3. 3
    Получите тип: ТипСсылки = ТипЗнч(Ссылка).
  4. 4
    Если нужен конкретный вид — сравните с Тип("ВидОбъекта.Имя"); если строка — возьмите Ссылка.Метаданные().ПолноеИмя().
  5. 5
    Отдельно проверьте Ссылка.Пустая(), если пустые ссылки должны обрабатываться иначе.
  6. 6
    Протестируйте код на реальных данных: справочник, документ, пустая ссылка, Неопределено, примитивное значение.

Для отладки удобно использовать конфигуратор: в табло (окно «Вычислить выражение») введите ТипЗнч(Переменная) и Ссылка.Метаданные().ПолноеИмя() — сразу видно и тип, и вид объекта без изменения кода. В пользовательском режиме тип ссылки можно косвенно определить по навигационной ссылке: команда ПолучитьНавигационнуюСсылку(Ссылка) вернёт строку вида e1cib/data/Справочник.Номенклатура?ref=..., где вид объекта указан явно.

Контрольные точки

Как проверить результат

Сравнение типов в коде
Норма

Условие срабатывает на тестовой ссылке нужного вида и не срабатывает на других видах

Тревожный признак

Условие никогда не выполняется — вероятно, сравнение со строкой или с неверным именем типа

Работа с пустой ссылкой
Норма

Тип определяется корректно, Метаданные() не падает

Тревожный признак

Исключение или тип «Неопределено» там, где ожидался вид объекта

Обработка Неопределено
Норма

Код отводит Неопределено в отдельную ветку до обращения к методам ссылки

Тревожный признак

Ошибка «Метод объекта не обнаружен (Метаданные)»

Ограничения и частые вопросы безопасности кода

Определение типа по ссылке — безопасная операция: она не обращается к базе данных за данными объекта и не изменяет ничего. Однако следующий за ней шаг — обращение к реквизитам через точку (Ссылка.Наименование) — уже выполняет чтение из базы. В циклах по тысячам ссылок это даёт заметную нагрузку; правильнее получать нужные поля одним запросом.

Ещё одно ограничение касается прав доступа. Сам тип ссылки виден всегда, но при попытке прочитать реквизиты объекта, на который у пользователя нет прав, возникнет ошибка или пустые значения в зависимости от режима. В универсальных обработках учитывайте это, особенно если код выполняется под разными ролями.

Итог

Что важно запомнить

ТипЗнч(Ссылка) вместе с Тип("ВидСсылка.Имя") — основной способ сравнения; Ссылка.Метаданные().ПолноеИмя() даёт имя вида строкой; принадлежность к классу проверяется через Метаданные.Документы.Содержит() и аналоги. Всегда отдельно обрабатывайте Неопределено и пустые ссылки, а в запросах используйте ТИПЗНАЧЕНИЯ и ТИП без слова «Ссылка».

Частые вопросы

Как определить тип ссылки, если значение может быть Неопределено?

Сначала проверьте значение: Если Значение = Неопределено Тогда — отведите отдельную ветку. Только после этого вызывайте ТипЗнч и Метаданные(). ТипЗнч(Неопределено) сам по себе не падает и возвращает тип «Неопределено», но обращение к Метаданные() вызовет исключение.

Чем отличаются типы СправочникСсылка и СправочникОбъект?

Ссылка — лёгкий идентификатор объекта, доступный без чтения данных из базы. Объект — полная в-memory копия данных, полученная через Ссылка.ПолучитьОбъект(). Это разные типы: ТипЗнч(Ссылка) и ТипЗнч(Ссылка.ПолучитьОбъект()) не равны, и сравнивать их нужно с соответствующими именами типов.

Как получить тип по строке с именем, например из настройки?

Используйте Тип("СправочникСсылка." + ИмяОбъекта). Если объект с таким именем не существует, функция вернёт Неопределено — обязательно проверьте результат перед сравнением. Альтернатива: найти метаданные через Метаданные.НайтиПоПолномуИмени() и работать уже с ними.

Можно ли определить тип ссылки в запросе без выгрузки результата?

Да. Функция ТИПЗНАЧЕНИЯ(Поле) возвращает тип прямо в запросе, оператор ССЫЛКА проверяет принадлежность к виду, а ТИП(Справочник.Имя) задаёт тип для сравнения. Обратите внимание: в запросе имя пишется без слова «Ссылка».

Как узнать тип объекта в пользовательском режиме без программирования?

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

Почему сравнение ТипЗнч(Ссылка) = "СправочникСсылка.Номенклатура" не работает?

Потому что слева объект типа «Тип», а справа строка — они никогда не равны. Строку нужно преобразовать в тип: ТипЗнч(Ссылка) = Тип("СправочникСсылка.Номенклатура"). Либо сравнивайте строки: Ссылка.Метаданные().ПолноеИмя() = "Справочник.Номенклатура".