Почему коллекция типов источника в подписке на событие пуста и как программно определить обобщенные типы менеджеров

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

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

Суть проблемы: пустой массив в ОписанииТипов

Проанализируем конкретный пример. В конфигурации существует подписка на событие ТарификацияОбработкаПолученияФормы. В качестве источника в ней указаны обобщенные типы: СправочникМенеджер, ДокументМенеджер, РегистрСведенийМенеджер и другие. На уровне работы приложения всё функционирует корректно — событие перехватывается для всех справочников и документов. Однако, если мы попытаемся программно проинспектировать эту подписку, мы столкнемся с неожиданным результатом.

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


ПодпискаМетаданные = Метаданные.ПодпискиНаСобытия.ТарификацияОбработкаПолученияФормы;
КоличествоТипов = ПодпискаМетаданные.Источник.Типы().Количество();
Сообщить("Количество типов: " + КоличествоТипов); // Результат будет: 0

Ситуация кажется парадоксальной: типы в конфигураторе выбраны, платформа их "понимает" при выполнении кода, но коллекция Типы() объекта ОписаниеТипов пуста. Более того, метод СодержитТип() также будет возвращать Ложь, даже если мы передадим туда правильный, казалось бы, тип.

Различие между конкретными и абстрактными типами менеджеров

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

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

Исследование через сериализацию и системные GUID

Чтобы понять, что на самом деле хранится внутри источника подписки, мы можем воспользоваться методом ЗначениеВСтрокуВнутр(). Это позволит нам заглянуть во внутреннее представление объекта ОписаниеТипов. Проанализируем результат сериализации такого "пустого" источника:


// Получаем внутреннюю строку описания типов источника
ВнутренняяСтрока = ЗначениеВСтрокуВнутр(ПодпискаМетаданные.Источник);
Сообщить(ВнутренняяСтрока);

В результате мы увидим структуру, содержащую странные идентификаторы (GUID). Например:

{"#",f5c65050-3bbb-11d5-b988-0050bae0a95d, {"Pattern", {"#",82faabf3-7f9b-4b2e-b499-98876415f270}, {"#",26dd1dee-252a-4942-b4b5-62ea44ed8030} } }

Здесь f5c65050-3bbb-11d5-b988-0050bae0a95d — это идентификатор самого класса ОписаниеТипов, а GUID внутри секции Pattern — это и есть те самые "невидимые" типы. Важно понимать, что эти идентификаторы являются фиксированными для платформы 1С. Они не меняются от конфигурации к конфигурации.

Таблица соответствия системных GUID базовым типам

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

Рассмотрим основные соответствия:

Обратите внимание, что идентификаторы для "Объектов" (например, СправочникОбъект) будут другими, но они обычно корректно отображаются в коллекции Типы(), если выбраны в метаданных.

Как программно проверить наличие типа в таком источнике?

Поскольку Источник.СодержитТип(Тип("СправочникМенеджер.Валюты")) вернет Ложь (так как в источнике указан абстрактный "любой менеджер", а не конкретный), нам нужны обходные пути. Разберем два варианта решения этой задачи.

Вариант 1: Использование строкового анализа

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


Функция ПодпискаСодержитВсеСправочники(ПодпискаОбъект)
    СтрокаТипов = ЗначениеВСтрокуВнутр(ПодпискаОбъект.Источник);
    Возврат Найти(СтрокаТипов, "82faabf3-7f9b-4b2e-b499-98876415f270") > 0;
КонецФункции

Вариант 2: Создание "эталонного" ОписанияТипов

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

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

Особенности события ОбработкаПолученияФормы

Стоит отдельно отметить, почему эта проблема наиболее остро проявляется именно в событии ОбработкаПолученияФормы. В традиционных событиях типа ПриЗаписи источником всегда является Объект (ссылочный тип данных). Эти типы платформа умеет отображать в коллекции Типы().

В событии ОбработкаПолученияФормы источником выступает Менеджер. Это фундаментальное отличие. Менеджер — это не данные в таблице БД, это программная сущность для управления этими данными. Именно при работе с менеджерами платформа чаще всего использует свои внутренние оптимизированные идентификаторы классов, что и приводит к "пустоте" коллекции типов в метаданных.

Подведем итоги

Мы выяснили, что отсутствие типов в программном доступе к метаданным подписки — это не ошибка конфигурации, а особенность реализации платформы 1С для обобщенных категорий менеджеров. Основные выводы нашего анализа:

  1. Метод Типы() возвращает пустой массив для системных групп (СправочникиМенеджер, ДокументыМенеджер и т.д.).
  2. Платформа оперирует фиксированными GUID для этих групп, которые можно увидеть через ЗначениеВСтрокуВнутр().
  3. Для программного анализа таких подписок необходимо использовать либо поиск по внутренним GUID, либо заранее подготовленные таблицы соответствий.
  4. Это поведение специфично для менеджеров и редко встречается при работе с обычными объектами или ссылками.

Знание этих внутренних механизмов позволяет разработчику создавать более гибкие инструменты для анализа конфигурации и понимания того, как на самом деле работают подписки на события "под капотом" платформы.

← На главную